WEBVTT 00:00:00.001 --> 00:00:05.340 Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds. 00:00:05.340 --> 00:00:09.880 This is episode 348, recorded August 15th, 2023. 00:00:09.880 --> 00:00:11.240 I'm Michael Kennedy. 00:00:11.240 --> 00:00:12.360 And I'm Brian Okken. 00:00:12.360 --> 00:00:15.660 And Brian, this episode is brought to everybody by us. 00:00:15.660 --> 00:00:21.360 I think you might be making a more concrete case for that than other times today. 00:00:21.360 --> 00:00:25.360 So, but yeah, check out all of our courses, books, things like that. 00:00:25.360 --> 00:00:28.840 It genuinely makes it possible for us to do this kind of stuff. 00:00:28.840 --> 00:00:32.000 Yeah, we love doing it, but yeah, also. 00:00:32.000 --> 00:00:33.240 Yeah, yeah, also. 00:00:33.240 --> 00:00:39.520 And if you want to be part of the live show and you're not watching live now, Tuesdays at 11, 00:00:39.520 --> 00:00:42.160 I go by set.fm slash live, all the details there. 00:00:42.160 --> 00:00:43.640 Brian, let's kick it off. 00:00:43.640 --> 00:00:44.720 What's your first item? 00:00:44.720 --> 00:00:49.500 Actually, I'm kind of on a packaging, a little bit of a packaging thing today. 00:00:49.500 --> 00:00:50.320 Okay, okay. 00:00:50.320 --> 00:00:56.140 Brett Cannon wrote an article called Differentiating Between Writing Down Dependencies to Use Packages 00:00:56.140 --> 00:00:58.740 and for Packages Themselves. 00:00:58.740 --> 00:01:00.060 It's kind of a big title. 00:01:00.060 --> 00:01:01.660 But here's the idea. 00:01:01.660 --> 00:01:03.280 And I've been thinking about this also. 00:01:03.280 --> 00:01:06.780 So I really, there's requirements.txt files. 00:01:06.780 --> 00:01:09.040 And those are often used for applications. 00:01:09.040 --> 00:01:13.140 And then there's, but that was really when we had like, 00:01:13.140 --> 00:01:16.300 that was either that or setup.py for packages. 00:01:16.600 --> 00:01:18.480 And now we have pyproject.toml. 00:01:18.480 --> 00:01:20.120 So can't we just use that? 00:01:20.120 --> 00:01:24.720 I mean, I kind of want to, but it doesn't quite work that way. 00:01:24.720 --> 00:01:30.880 You install dependencies with a pyproject.toml by doing a pip installing your package. 00:01:30.880 --> 00:01:33.840 And you can install it like pip install.e. 00:01:34.200 --> 00:01:36.920 I think, yeah, pip install.e. 00:01:36.920 --> 00:01:38.540 dash e, right. 00:01:38.540 --> 00:01:42.600 And on the current directory, or you can give it a local project directory. 00:01:42.600 --> 00:01:47.720 And you can even do optional things like optional test dependencies and stuff. 00:01:47.720 --> 00:01:54.000 And I think when you do the dash e, it installs your optional test dependencies also. 00:01:54.000 --> 00:01:54.780 I'm not sure. 00:01:54.780 --> 00:01:57.940 But, and I'm used to that because I do packages also. 00:01:57.940 --> 00:02:00.660 But we still have the requirements.txt file. 00:02:00.660 --> 00:02:02.480 There really are for different things. 00:02:02.480 --> 00:02:06.840 So Brett has talks about this a lot in here. 00:02:06.840 --> 00:02:11.940 And looking at why there's a thing called like project dependencies. 00:02:11.940 --> 00:02:15.440 And the project is really meant for packaging. 00:02:15.440 --> 00:02:18.860 It's really meant just for the whole packaging system. 00:02:18.860 --> 00:02:23.540 So that when you install something, install a wheel, 00:02:23.540 --> 00:02:26.300 it knows how to get packages for it. 00:02:26.300 --> 00:02:26.900 That's it. 00:02:26.900 --> 00:02:28.820 It's not supposed to be for applications. 00:02:28.820 --> 00:02:33.440 So really, that's kind of the discussion around here, around this article. 00:02:33.440 --> 00:02:35.520 However, there's a couple ideas. 00:02:35.520 --> 00:02:42.020 He references, also references back a Donald Stuffed article from 2013 00:02:42.020 --> 00:02:45.600 about setup.py versus requirements.txt. 00:02:45.600 --> 00:02:47.680 But like I said, that was setup.py. 00:02:47.680 --> 00:02:50.540 Maybe we could do something better. 00:02:50.540 --> 00:02:55.220 Brett's consideration is maybe we could have some standard, 00:02:55.860 --> 00:02:59.640 something, some other file that we could have. 00:02:59.640 --> 00:03:05.740 I personally, I think that maybe we could expand PyProject.toml. 00:03:05.740 --> 00:03:07.160 I really like the Toml thing. 00:03:07.160 --> 00:03:10.240 So maybe we could either have a requirements.toml, 00:03:10.560 --> 00:03:15.580 or maybe we could have like instead of a project section of the Toml file, 00:03:15.580 --> 00:03:18.820 maybe we could have maybe an application section. 00:03:18.820 --> 00:03:19.760 Maybe that would work. 00:03:20.020 --> 00:03:20.180 Yeah. 00:03:20.180 --> 00:03:25.780 So yeah, I think like a dev requirements even just in the PyProject.toml 00:03:25.780 --> 00:03:27.040 seems pretty straightforward to me. 00:03:27.040 --> 00:03:27.560 Yeah. 00:03:27.560 --> 00:03:35.320 I mean, I run into it in other places too, like just in a Git repo that has like a couple Python 00:03:35.320 --> 00:03:38.560 tools in it that people can install on their own. 00:03:38.560 --> 00:03:40.500 But they might have some requirements. 00:03:40.500 --> 00:03:41.540 How do you list those? 00:03:41.540 --> 00:03:42.780 Do you stick them as applications? 00:03:42.780 --> 00:03:50.460 I mean, requirements.txt is normally the thing that's used for like Django web applications and 00:03:50.460 --> 00:03:51.580 things like that. 00:03:51.580 --> 00:03:55.540 So maybe requirements.txt is fine, but I think. 00:03:55.540 --> 00:03:55.980 Perhaps. 00:03:55.980 --> 00:04:01.780 What I have is I have for my world, I have requirements.txt, which is like from the web apps and stuff. 00:04:01.780 --> 00:04:05.200 That is what is required for the app to run without that. 00:04:05.200 --> 00:04:05.760 Yeah. 00:04:05.760 --> 00:04:06.800 You can't make it go. 00:04:06.800 --> 00:04:09.040 Then I have requirements-dev.txt. 00:04:09.040 --> 00:04:10.140 I've seen that pattern a lot. 00:04:10.140 --> 00:04:14.660 And then to actually generate those, I use pip-tools and pip compile. 00:04:14.660 --> 00:04:17.520 So I have requirements.in and requirements-dev.in. 00:04:17.620 --> 00:04:21.680 And then I can auto-update all the dependencies and keep them in sync. 00:04:21.680 --> 00:04:22.320 Yeah. 00:04:22.320 --> 00:04:23.560 That's how I do it these days. 00:04:23.560 --> 00:04:33.640 But now even people with Django or other things are using a PyProjectTunnel also to store their 00:04:33.640 --> 00:04:35.600 black settings and things like that. 00:04:35.600 --> 00:04:41.540 So we're kind of using the PyProjectTunnel for more things. 00:04:41.540 --> 00:04:43.440 And I think maybe we could extend it for this. 00:04:43.440 --> 00:04:44.700 Anyway, that's my hope. 00:04:44.700 --> 00:04:45.120 It seems reasonable. 00:04:45.120 --> 00:04:45.460 Yeah. 00:04:45.800 --> 00:04:48.160 So anyway, what do you got for us? 00:04:48.160 --> 00:04:51.280 Well, let's monkey around a little bit with the Python monkey. 00:04:51.280 --> 00:04:52.960 With the Python monkey. 00:04:52.960 --> 00:04:53.640 That's cute. 00:04:53.640 --> 00:04:54.060 That's cute. 00:04:54.060 --> 00:04:54.800 It is. 00:04:54.800 --> 00:05:00.220 So this comes to us from created by Will Pringle, I believe, amongst others. 00:05:00.220 --> 00:05:01.200 Let's see. 00:05:01.200 --> 00:05:03.660 On the contributors here. 00:05:03.660 --> 00:05:05.560 There. 00:05:05.560 --> 00:05:06.000 Yeah. 00:05:06.000 --> 00:05:06.920 There we go. 00:05:06.920 --> 00:05:07.360 Yeah. 00:05:07.460 --> 00:05:09.240 So a bunch of folks that work on this project. 00:05:09.240 --> 00:05:15.740 It's not super popular with only 276 stars, but I think it might be a pretty darn interesting 00:05:15.740 --> 00:05:18.260 compatibility layer for Python. 00:05:18.260 --> 00:05:19.580 So what do I mean by that? 00:05:19.580 --> 00:05:23.780 So imagine I'm, you can look at this from two perspectives. 00:05:24.160 --> 00:05:26.660 So don't scoff at one if you prefer the other. 00:05:26.660 --> 00:05:41.580 So imagine I'm a JavaScript developer and I've got a ton of cool JavaScript code that not just for the web front end, but, you know, kind of in the node JS sense, like a bunch of utilities or a bunch of libraries that work and do certain things. 00:05:41.580 --> 00:05:41.860 Right. 00:05:41.860 --> 00:05:42.260 Yeah. 00:05:42.260 --> 00:05:45.780 But I also have a Python app and I'd like to somehow use those together. 00:05:45.780 --> 00:05:49.020 So Python monkey is a straight way to put it. 00:05:49.020 --> 00:06:00.920 It, it basically hosts job, a JavaScript, a full on high performance JavaScript, JIT compiled to almost native performance JavaScript engine inside of Python through pip install. 00:06:00.920 --> 00:06:15.860 So if I wanted to use some of the JavaScript code, I just write my Python application and for that function or that functionality, I just import the job, you know, first spider monkey or Python monkey. 00:06:15.860 --> 00:06:20.260 And then I import the JavaScript files that you would use. 00:06:20.260 --> 00:06:22.300 And then you just call them like Python functions. 00:06:22.300 --> 00:06:23.240 Okay. 00:06:23.560 --> 00:06:37.180 Or reverse, I'm writing a Python application and you know, one option to make like slow loops go faster would be to write that in Cython and Cython is getting better with the Cython three release that we discussed already previous episode. 00:06:37.180 --> 00:06:48.160 But JavaScript, because this thing, the spider monkey JavaScript engine is the one that I believe Firefox uses does JIT compilation to native code. 00:06:48.160 --> 00:06:50.780 It basically is near native performance as well. 00:06:50.780 --> 00:06:56.360 So if you'd like, you could rewrite that part in TypeScript or JavaScript and run just that section. 00:06:56.360 --> 00:07:00.700 And it uses things like shared memory between JavaScript and Python. 00:07:00.700 --> 00:07:06.680 So if you've got like a string or a list, those are, those are the same objects, which is pretty crazy. 00:07:06.680 --> 00:07:07.300 Wow. 00:07:07.300 --> 00:07:08.280 At least for the strings. 00:07:08.280 --> 00:07:08.720 Okay. 00:07:08.720 --> 00:07:11.200 So, let's look at some examples. 00:07:11.200 --> 00:07:14.720 There's an article by will and no, I will not log into medium. 00:07:14.720 --> 00:07:15.740 You're partially evil. 00:07:15.740 --> 00:07:16.140 Okay. 00:07:16.140 --> 00:07:17.960 So here's an article by, 00:07:19.640 --> 00:07:22.880 my will here says, look at, let's look at some code examples. 00:07:22.880 --> 00:07:23.300 All right. 00:07:23.300 --> 00:07:25.520 So import Python monkey as PM. 00:07:25.520 --> 00:07:30.140 And then you say PM eval and give it JavaScript code and then boom, it runs that. 00:07:30.140 --> 00:07:31.200 That's one way. 00:07:31.200 --> 00:07:33.980 what you can do maybe is more interesting is look at this. 00:07:33.980 --> 00:07:38.400 I can say, em dot eval and give it an anonymous JavaScript function. 00:07:38.640 --> 00:07:44.100 And then what comes back, not evaluating it, but just the thing to define the function in JavaScript. 00:07:44.100 --> 00:07:44.400 Okay. 00:07:44.400 --> 00:07:48.240 And then what comes back is an object that itself is a function. 00:07:48.240 --> 00:07:49.300 Okay. 00:07:49.440 --> 00:07:50.620 So that's pretty cool. 00:07:50.620 --> 00:07:51.120 Yeah. 00:07:51.120 --> 00:07:52.980 like, and hold on. 00:07:52.980 --> 00:07:53.920 There's two parts of this. 00:07:53.920 --> 00:07:56.640 So I've got a, I've created a JavaScript function. 00:07:56.640 --> 00:07:59.940 That's jet compiled in spider monkey through this eval. 00:08:00.100 --> 00:08:04.100 And what the, I didn't say this part, what the function takes is given a function. 00:08:04.100 --> 00:08:07.760 It will call that function passing hello world to it. 00:08:07.760 --> 00:08:08.300 Okay. 00:08:08.300 --> 00:08:09.200 The string hello world. 00:08:09.200 --> 00:08:09.560 Okay. 00:08:09.700 --> 00:08:14.840 So what you do is you get the function back as a Python function and then they pass print. 00:08:14.840 --> 00:08:19.820 It somehow proxies the print function into the JavaScript space. 00:08:19.820 --> 00:08:24.840 And then JavaScript calls the Python print, which it then comes back to the console, to the terminal. 00:08:24.840 --> 00:08:25.360 Wow. 00:08:25.360 --> 00:08:26.040 Oh, okay. 00:08:26.040 --> 00:08:27.560 That's some deep integration, right? 00:08:27.560 --> 00:08:29.780 That's some pretty, pretty wild stuff. 00:08:29.780 --> 00:08:31.000 let's see. 00:08:31.000 --> 00:08:32.220 What else can we do here? 00:08:32.220 --> 00:08:33.400 This is pretty interesting. 00:08:33.400 --> 00:08:39.500 I can say, given a JavaScript module, like I described, I can, you know, here's a example. 00:08:39.600 --> 00:08:41.780 It has a say hello export. 00:08:41.780 --> 00:08:45.180 Then you can just say PM dot require that JavaScript module. 00:08:45.180 --> 00:08:50.700 And now you've got all the function, all the export behavior from that JavaScript module. 00:08:50.700 --> 00:08:51.460 Right. 00:08:51.460 --> 00:08:52.120 Which is cool. 00:08:52.120 --> 00:08:55.600 yeah, there's, there's some more examples in here. 00:08:55.600 --> 00:08:57.360 The other angle that's pretty interesting. 00:08:57.360 --> 00:09:01.340 There's two more angles that are interesting because it uses spider monkey and spider monkey 00:09:01.340 --> 00:09:03.300 is awesome with WebAssembly. 00:09:03.300 --> 00:09:09.380 It allows you to run, untrusted WASM code from languages like C, C++ and rust. 00:09:09.500 --> 00:09:15.740 You can now basically do, any, you can call any WebAssembly code as well that you'd 00:09:15.740 --> 00:09:17.220 like inside of your function. 00:09:17.220 --> 00:09:18.160 Now we're getting interesting. 00:09:18.160 --> 00:09:18.900 Yeah. 00:09:18.900 --> 00:09:23.740 It supports things like async and await using the async and await keywords to handle the 00:09:23.740 --> 00:09:25.340 callback nature of JavaScript. 00:09:25.420 --> 00:09:30.320 like the dot then type of deferreds and different things. 00:09:30.320 --> 00:09:33.000 So you can just async and await those behaviors, right? 00:09:33.000 --> 00:09:36.700 Just await a WebAssembly call, which is pretty excellent. 00:09:36.700 --> 00:09:37.260 Yeah. 00:09:37.260 --> 00:09:40.920 So there's a bunch of, examples, some pretty cool graphics here. 00:09:42.660 --> 00:09:48.600 with Spock and, captain Kerr going my mind to your mind, my object, the your dicks, your 00:09:48.600 --> 00:09:50.080 dicks to my objects. 00:09:50.080 --> 00:09:51.160 It's pretty awesome. 00:09:51.160 --> 00:09:51.480 There. 00:09:51.480 --> 00:09:57.620 another angle that is worth considering is this allows the entire Python data science 00:09:57.620 --> 00:09:59.900 stack to become accessible to JavaScript developers. 00:09:59.900 --> 00:10:01.600 developers, right? 00:10:01.600 --> 00:10:01.940 Yeah. 00:10:01.940 --> 00:10:05.900 So if you, if you want to use, you know, the machine learning stuff, if you want to use 00:10:05.900 --> 00:10:07.820 pandas or pollers, right. 00:10:07.820 --> 00:10:11.600 You just write your code and then, you know, do the integration here. 00:10:11.600 --> 00:10:13.460 And yeah, that's, that's pretty much it. 00:10:13.460 --> 00:10:19.000 it, it finishes with, some funny little pictures here of, no on the arc. 00:10:19.720 --> 00:10:23.020 Got a Python and a JavaScript, which looks like a penguin. 00:10:23.020 --> 00:10:24.520 And then it has the Python monkey. 00:10:24.520 --> 00:10:25.500 The what, what is that? 00:10:25.500 --> 00:10:26.360 What the heck is this? 00:10:26.360 --> 00:10:26.740 All right. 00:10:26.740 --> 00:10:33.460 Anyway, that's, that's Python monkey, which is, I think, potentially interesting. 00:10:33.460 --> 00:10:38.380 So with the, with the WebAssembly and stuff, you could potentially have like every other 00:10:38.380 --> 00:10:42.140 function in your system be implemented by a different language. 00:10:42.140 --> 00:10:49.280 I'm bored of, C, C++ rust go. 00:10:49.500 --> 00:10:51.180 what else do we want to write it in? 00:10:51.180 --> 00:10:51.540 Yeah. 00:10:51.540 --> 00:10:52.540 Why not everything? 00:10:52.540 --> 00:10:56.800 just make sure that your, your application is only maintainable by you. 00:10:56.800 --> 00:10:57.280 That'd be. 00:10:57.280 --> 00:10:57.960 Exactly. 00:10:57.960 --> 00:10:59.880 Like, do you know how many compilers you need to do this? 00:10:59.880 --> 00:11:00.720 No, this is a mall. 00:11:00.720 --> 00:11:03.980 That's kind of fun to, to joke about, but this does look pretty cool. 00:11:03.980 --> 00:11:04.700 So yeah. 00:11:04.700 --> 00:11:06.060 Yeah, it does look pretty cool. 00:11:06.060 --> 00:11:08.640 So, you know, congrats to the folks there. 00:11:08.640 --> 00:11:10.160 This maybe it'll go somewhere. 00:11:10.160 --> 00:11:10.520 We'll see. 00:11:10.520 --> 00:11:11.620 It's, it's pretty interesting. 00:11:11.620 --> 00:11:18.540 I think, also it's, it's worth noting, that there is, somewhere in here that there's 00:11:18.540 --> 00:11:19.540 a comparison to other things. 00:11:19.540 --> 00:11:25.440 So this apparently is not the only time such a type of creation, has been attempted. 00:11:25.440 --> 00:11:29.460 So it says there are other projects that already do JavaScript and Python, such as JS to PI, 00:11:29.460 --> 00:11:31.040 PI V8 and medical. 00:11:31.200 --> 00:11:33.960 But there's a bunch of different drawbacks or stuff. 00:11:33.960 --> 00:11:36.620 And so this is why we created it basically in addition. 00:11:36.620 --> 00:11:42.360 So JS to PI is implemented entirely in Python, which sounds awesome, except, you know, V8 and 00:11:42.360 --> 00:11:45.360 spider monkey compiled a native code and run ultra fast. 00:11:45.360 --> 00:11:48.720 Whereas, you know, if you just run in Python, it probably doesn't have any of those things. 00:11:48.720 --> 00:11:49.020 Right. 00:11:49.020 --> 00:11:56.480 PI V8, has a wrapper around Google's V8 JavaScript engine, which is great, but it's just super low level. 00:11:56.480 --> 00:12:02.040 You just like talk directly to the JavaScript bits, which for things, for example, doesn't have async and await. 00:12:02.040 --> 00:12:10.280 And finally medical is extensible, embeddable and interoperable, but you've got to install a bunch of different run times outside of just pip install. 00:12:10.340 --> 00:12:16.140 So anyway, if people are going, but it exists, it does, but this apparently is why it exists like this. 00:12:16.140 --> 00:12:17.200 Yep. 00:12:17.200 --> 00:12:17.660 Cool. 00:12:17.660 --> 00:12:18.100 Yeah. 00:12:18.100 --> 00:12:22.880 And John out in the audience says, I do this, but going the other way using transcript. 00:12:22.880 --> 00:12:23.940 Okay. 00:12:23.940 --> 00:12:24.700 Interesting. 00:12:24.700 --> 00:12:26.860 Something else to, something new to check out. 00:12:26.860 --> 00:12:27.300 Thanks, John. 00:12:27.300 --> 00:12:28.440 We'll take that out. 00:12:28.440 --> 00:12:28.840 So. 00:12:28.840 --> 00:12:29.340 All right. 00:12:29.340 --> 00:12:30.160 Over to you, Brian. 00:12:30.420 --> 00:12:38.180 well, I just, one more thing, Olivero, says, Python monkey perfect for works on my machine certification. 00:12:38.180 --> 00:12:40.920 There, there is an official works on my machine certification. 00:12:40.920 --> 00:12:42.820 If you have, I know we talked about it before. 00:12:42.820 --> 00:12:43.800 It's glorious. 00:12:43.800 --> 00:12:44.740 It comes with a sticker. 00:12:44.740 --> 00:12:52.800 Power your application code, getting the latest version of any recent changes from other developers, purely optional and not a requirement for certification. 00:12:53.200 --> 00:12:58.180 Launch the application cause one code path in the code you're checking to be executed. 00:12:58.180 --> 00:13:00.880 The preferred way to do this is with ad hoc manual testing. 00:13:00.880 --> 00:13:02.080 You can omit this step. 00:13:02.080 --> 00:13:08.760 If the code change is less than five lines, or if in the developer's professional opinion, the code could not possibly result in an error. 00:13:08.760 --> 00:13:10.460 Check your code into version control. 00:13:10.460 --> 00:13:11.280 You're certified. 00:13:11.280 --> 00:13:13.100 Yeah. 00:13:13.100 --> 00:13:13.460 There we go. 00:13:13.460 --> 00:13:14.640 Two jokes in one episode. 00:13:14.640 --> 00:13:15.600 How that, how about that? 00:13:15.600 --> 00:13:16.060 Awesome. 00:13:16.060 --> 00:13:20.900 Well, we had a little bit more, some, a little more humor, to add to it. 00:13:21.080 --> 00:13:26.700 So because, I thought it was a serious article and it is, it's just funny and weird. 00:13:26.700 --> 00:13:33.980 So Seth Larson wrote, quirks of Python packaging, versioning package, Python package versioning. 00:13:33.980 --> 00:13:34.400 That's it. 00:13:34.400 --> 00:13:48.960 so we're used to, well, we're kind of getting used to, the world where we all have some ver like 1.2.3 and for semantic versioning, but we also have calendar versioning like 2023.6.1. 00:13:48.960 --> 00:13:55.480 And then there's stuff like you can add a pre-release suffix and things like that, but it gets way weirder and fun. 00:13:55.480 --> 00:14:01.920 so, and I have noticed this, especially with get up, like get get up versioning. 00:14:01.920 --> 00:14:04.700 Sometimes people will do, V versioning. 00:14:04.700 --> 00:14:06.800 So there's V prefixes you can do. 00:14:06.800 --> 00:14:12.240 And some, I guess you can pull that into your, your Python application version as well. 00:14:12.240 --> 00:14:12.740 Why not? 00:14:13.360 --> 00:14:17.160 so V versions are allowed, epic versions. 00:14:17.160 --> 00:14:18.840 Did you know about epic versions? 00:14:18.840 --> 00:14:19.980 I just learned about this. 00:14:19.980 --> 00:14:21.020 I don't think so. 00:14:21.020 --> 00:14:30.240 So it's, you can, you can have a, a exclamation point separating your epic from the rest of your version. 00:14:30.240 --> 00:14:38.140 So this is, so like one bang 2.0.0 would be epic one version 2.0.0. 00:14:38.140 --> 00:14:38.680 Um, 00:14:38.680 --> 00:14:43.660 I got to tell you, I already had a hard time deciding when the two or when the middle zero or the last zero changes. 00:14:43.760 --> 00:14:47.360 If I put a number in front of an exclamation point, I'm going to just lost. 00:14:47.360 --> 00:14:47.960 Yeah. 00:14:47.960 --> 00:14:48.760 Apparently. 00:14:48.760 --> 00:14:49.500 Too much decision. 00:14:49.500 --> 00:14:50.200 Too many decisions. 00:14:50.200 --> 00:14:55.620 Apparently some systems use colons for epics, but Python chose, this is all based on Python 00:14:55.620 --> 00:14:56.800 PEP 440. 00:14:56.800 --> 00:15:03.220 and, the, yeah, apparently we chose the bang symbol or is that spang, right? 00:15:03.220 --> 00:15:05.320 the exclamation point. 00:15:05.320 --> 00:15:08.240 so, and that just kind of looks like a one. 00:15:08.240 --> 00:15:10.600 If you did one bang one, that would be hard to tell. 00:15:10.600 --> 00:15:12.240 local versions. 00:15:12.500 --> 00:15:17.000 and is you can, you can extend after you have versions, you're going to have alpha 00:15:17.000 --> 00:15:20.160 numerics and, other stuff. 00:15:20.160 --> 00:15:24.380 like, you know, here, plus, I don't know if the plus is part of it anyway. 00:15:24.380 --> 00:15:30.920 so after your normal version, like 1.0.0, he has an example of plus Ubuntu dash one. 00:15:30.920 --> 00:15:37.920 this gets normalized, but, but, and luckily, but this is kind of nice for local 00:15:37.920 --> 00:15:40.220 it's local versions because pipe AI doesn't like it. 00:15:40.360 --> 00:15:45.020 So pipe AI will not let you push up local versions to guy, which is probably right. 00:15:45.020 --> 00:15:49.120 local builds, long versions. 00:15:49.120 --> 00:15:54.960 Apparently you can use the, use the first 217 digits of PI and that works fine. 00:15:54.960 --> 00:16:00.580 as, as one of the digits, there's no limits, case insensitivity. 00:16:00.960 --> 00:16:02.420 so yeah. 00:16:02.420 --> 00:16:02.760 Okay. 00:16:02.760 --> 00:16:03.420 That's fine. 00:16:03.420 --> 00:16:10.560 it gets normalized lower or something so that you, you know, capital RC one is the 00:16:10.560 --> 00:16:12.260 same as lowercase RC one. 00:16:12.260 --> 00:16:13.400 That's, that's appropriate. 00:16:13.820 --> 00:16:17.940 so pre-release I've seen, I've actually used pre post. 00:16:17.940 --> 00:16:22.660 I don't know if I use pre I've seen pre and I've used post release occasionally, although 00:16:22.660 --> 00:16:25.620 it's so weird that people don't understand what's going on. 00:16:25.620 --> 00:16:26.940 So I don't do that anymore. 00:16:27.260 --> 00:16:31.460 but apparently pre post and dev are not mutually exclusive. 00:16:31.460 --> 00:16:35.300 You can have, but all three, allowed in one version. 00:16:35.300 --> 00:16:37.380 Why would you do that? 00:16:37.380 --> 00:16:41.960 so, and, yeah, no delimiters needed. 00:16:41.960 --> 00:16:44.460 there's just a lot of fun here. 00:16:44.460 --> 00:16:45.740 thanks. 00:16:45.740 --> 00:16:47.740 So implicit hyphens are allowed. 00:16:47.740 --> 00:16:50.140 So this is both the serious and non-serious. 00:16:50.140 --> 00:16:52.280 Oh, implicit zeros are weird. 00:16:52.280 --> 00:17:01.860 So, you can, you can, if you have a version 2.0.4, you can just keep adding a bunch of 0.0.0.0 00:17:01.860 --> 00:17:03.180 and it works fine. 00:17:03.180 --> 00:17:05.040 It resolves to 2.0.4. 00:17:05.040 --> 00:17:05.820 That's awesome. 00:17:05.820 --> 00:17:13.180 I, I definitely need to advertise some version say, just, just pick up 2.0.3. 00:17:13.460 --> 00:17:15.560 0.0.0.0. 00:17:15.560 --> 00:17:17.600 Yeah. 00:17:17.600 --> 00:17:18.940 It looks, makes it sound tough. 00:17:18.940 --> 00:17:19.240 Like, yeah. 00:17:19.240 --> 00:17:20.440 I mean, in releases we've had. 00:17:20.440 --> 00:17:24.180 Anyway, totally, totally fun articles. 00:17:24.180 --> 00:17:24.880 So thanks, Seth. 00:17:24.880 --> 00:17:25.860 Brian, do you hear that? 00:17:25.860 --> 00:17:26.460 No. 00:17:26.460 --> 00:17:29.800 That's the sound of a million regexes dying. 00:17:29.800 --> 00:17:35.520 That are supposed to be scanning for the version string in your code. 00:17:35.520 --> 00:17:36.060 Yeah. 00:17:36.060 --> 00:17:40.780 But maybe that's why Python just has it as a string. 00:17:40.780 --> 00:17:44.500 It's, if you do dunder version equals, it's, just a string. 00:17:44.500 --> 00:17:44.780 So. 00:17:44.780 --> 00:17:45.280 Yeah. 00:17:46.300 --> 00:17:51.980 Axel asks, if you use C++ compiled code, so I guess native code, that's like not part 00:17:51.980 --> 00:17:53.460 of just source only Python. 00:17:53.460 --> 00:17:56.560 Is there a way to define which compiler you use in the versioning? 00:17:56.560 --> 00:18:01.060 Maybe that Ubuntu type variant, that local version, but you can't publish that, right? 00:18:01.060 --> 00:18:04.120 you can't push it to PyPI like that. 00:18:04.240 --> 00:18:10.320 But like, for instance, it's a, I'm not sure how this, this relates to, like 00:18:10.320 --> 00:18:13.540 the wheel naming, the wheel download naming thing. 00:18:13.540 --> 00:18:13.780 Yeah. 00:18:13.780 --> 00:18:15.020 so. 00:18:15.020 --> 00:18:18.300 I'm sure there's some metadata you could put in there, right? 00:18:18.300 --> 00:18:20.400 Like you can do dunder version, right? 00:18:20.400 --> 00:18:23.760 You could just do dunder compiler and say, you know, print that out and it'll tell you, 00:18:23.840 --> 00:18:26.660 but it's not, there's no standard that I can think of. 00:18:26.660 --> 00:18:29.740 Well, there's the, there is the wheel standard. 00:18:29.740 --> 00:18:31.900 I just don't remember where the link is. 00:18:31.900 --> 00:18:33.080 But that's more platform based, right? 00:18:33.080 --> 00:18:34.340 Than a compiler. 00:18:34.340 --> 00:18:35.260 Oh, right. 00:18:35.260 --> 00:18:36.320 It's not compiler based. 00:18:36.320 --> 00:18:37.360 It's platform based. 00:18:37.360 --> 00:18:41.500 I mean, the compilers got to compile to the platform, but it, it doesn't say like use GCC 00:18:41.500 --> 00:18:45.700 versus LLVM, Clang, Visual Studio, whatever, right? 00:18:45.700 --> 00:18:46.040 Right. 00:18:46.040 --> 00:18:46.500 Yeah. 00:18:46.500 --> 00:18:48.400 And usually I'm just doing pure Python. 00:18:48.400 --> 00:18:51.620 So I have all listed, but the wheel, anyway. 00:18:51.620 --> 00:18:52.360 Exactly. 00:18:52.360 --> 00:18:52.960 So. 00:18:52.960 --> 00:18:53.440 Exactly. 00:18:53.440 --> 00:18:54.720 All right. 00:18:54.720 --> 00:18:59.480 Well, with all that, Python monkeying around, I could just barely stand it. 00:18:59.480 --> 00:19:00.540 Oh dear. 00:19:00.540 --> 00:19:01.960 About bear type. 00:19:01.960 --> 00:19:02.600 Nice. 00:19:02.600 --> 00:19:04.320 The bear metal type checker. 00:19:04.320 --> 00:19:04.900 Okay. 00:19:04.900 --> 00:19:08.660 So people know I'm a huge fan of types, Python type hints and all those things. 00:19:08.660 --> 00:19:13.380 They're, they're super, super empowering and make the editors so much more helpful. 00:19:13.380 --> 00:19:18.480 It means you don't have to go into, the documentation and go, what does this take again? 00:19:18.480 --> 00:19:21.640 I know it takes an, an ARGs here, but is ARGs a dictionary? 00:19:21.640 --> 00:19:22.560 Is it a class? 00:19:22.640 --> 00:19:23.460 Is it a string? 00:19:23.460 --> 00:19:24.900 Is it an, I, what is it? 00:19:24.900 --> 00:19:25.160 Right? 00:19:25.160 --> 00:19:26.320 Like crazy stuff like that. 00:19:26.320 --> 00:19:26.480 Right? 00:19:26.480 --> 00:19:26.680 Yeah. 00:19:26.680 --> 00:19:31.920 So types are awesome for conveying that information without asking go to the docs or some other 00:19:31.920 --> 00:19:33.140 place to figure it out. 00:19:33.140 --> 00:19:42.360 However, what Python type hints, annotations generally don't do as the word hint would indicate. 00:19:42.360 --> 00:19:48.040 You can use tools like my PI and my PI will say the typing looks consistent or inconsistent, 00:19:48.040 --> 00:19:52.520 but regardless of what it says, when you run the code, whether or not the typing is consistent, 00:19:52.520 --> 00:19:56.680 long as it actually still semantically valid, it's going to run. 00:19:56.680 --> 00:20:01.540 Even if you tell the types, it takes a string, but you really pass an int and it did plus to 00:20:01.540 --> 00:20:02.300 it, but you know what? 00:20:02.300 --> 00:20:04.620 You pass two integers and two strings and it still worked. 00:20:04.620 --> 00:20:05.080 Right? 00:20:05.080 --> 00:20:09.920 So the runtime version of typing and Python is mostly absent, right? 00:20:09.920 --> 00:20:12.100 Excluding things like Pydantic and a few others. 00:20:12.200 --> 00:20:19.920 So this bear type thing is a near zero cost, near real time, pure Python runtime type checker 00:20:19.920 --> 00:20:25.280 that makes runtime mismatches for typing runtime errors. 00:20:25.280 --> 00:20:26.000 Interesting. 00:20:26.000 --> 00:20:26.500 Okay. 00:20:26.500 --> 00:20:30.560 So you can say, this sounds like a horrible idea and I will never touch it. 00:20:30.560 --> 00:20:32.860 Please don't, you know, install the bear. 00:20:32.860 --> 00:20:38.340 Or you could say, I come from a static language and this dynamic typing business is freaking me 00:20:38.340 --> 00:20:38.540 out. 00:20:38.540 --> 00:20:39.680 Can we get a little closer? 00:20:39.680 --> 00:20:40.720 Then you can have it. 00:20:40.780 --> 00:20:43.980 I feel like this is the kind of thing that for little projects is completely useless, 00:20:43.980 --> 00:20:47.280 but for huge projects, it may be, it starts to become more valuable. 00:20:47.280 --> 00:20:47.560 Right? 00:20:47.560 --> 00:20:48.000 Yeah. 00:20:48.000 --> 00:20:53.920 So if you just jump right into it, you pip install bear type, and then you can do things 00:20:53.920 --> 00:20:59.260 like, import the decorator and just put a decorator onto a function that has a type 00:20:59.260 --> 00:21:01.600 annotation or hint right there like that. 00:21:01.600 --> 00:21:07.920 So here's one that says quote Wiggum and then it passes lines in the type declaration says 00:21:07.920 --> 00:21:10.640 lines is a list of stir and it returns none. 00:21:10.640 --> 00:21:11.140 Okay. 00:21:11.140 --> 00:21:11.140 Okay. 00:21:11.140 --> 00:21:16.100 So then if you just use this function, pass it a list of strings, it just runs. 00:21:16.100 --> 00:21:16.440 Right? 00:21:16.440 --> 00:21:16.900 Yeah. 00:21:16.900 --> 00:21:22.100 If however, though you pass it a list of bytes, which kind of look like strings, but are not 00:21:22.100 --> 00:21:27.240 strings, you get an exception that says parameter such and such and such. 00:21:27.240 --> 00:21:28.140 Um, 00:21:28.140 --> 00:21:28.140 Um, 00:21:28.140 --> 00:21:32.760 it gives you the actual index in the list. 00:21:32.760 --> 00:21:36.140 It says list item zero with this value is not a string. 00:21:36.140 --> 00:21:38.980 Cause it's a B string, which is really bytes, right? 00:21:38.980 --> 00:21:39.480 Yeah. 00:21:39.480 --> 00:21:40.440 It's pretty cool, right? 00:21:40.440 --> 00:21:42.020 Yeah, it is really cool. 00:21:42.020 --> 00:21:50.080 and I, I'm kind of, agreeing with, Alvaro, said, maybe, maybe running 00:21:50.080 --> 00:21:51.200 with the test suite. 00:21:51.200 --> 00:21:57.160 And I was thinking maybe dynamically add these somehow, use the bare types during 00:21:57.160 --> 00:22:02.960 development and maybe, maybe take them off later if it, but if it's really fast, 00:22:02.960 --> 00:22:03.440 yeah. 00:22:03.700 --> 00:22:05.940 Yeah, I'll, I'll comment on that in a second. 00:22:05.940 --> 00:22:08.060 there are also validators. 00:22:08.060 --> 00:22:10.720 There's an is and an annotated validator. 00:22:10.720 --> 00:22:16.260 If you want to be more restrictive, maybe even then you might expect it's part of Python, but 00:22:16.260 --> 00:22:19.180 it's not a commonly known part of the type and then thing. 00:22:19.180 --> 00:22:25.200 So for example, I could define a new type using annotated called list of strings. 00:22:25.200 --> 00:22:25.820 Okay. 00:22:26.040 --> 00:22:31.920 And it says, it has to be a list of strings as one part of the annotation. 00:22:31.920 --> 00:22:37.640 And then another one is, well, if it's, it has to be a non-empty set of strings is what 00:22:37.640 --> 00:22:38.920 they're trying to create here. 00:22:38.920 --> 00:22:39.440 Okay. 00:22:39.440 --> 00:22:43.940 So it says if it's a list with a bunch of stuff, the bunch of stuff has to be strings, 00:22:43.940 --> 00:22:49.840 but it also contests that it's not falsy, which would be the case when it's a just, you 00:22:49.840 --> 00:22:51.440 know, zero length list. 00:22:51.440 --> 00:22:53.920 So then you can annotate with that type. 00:22:54.020 --> 00:22:58.900 And if you call with regular somewhere, you call it with a regular code is fine. 00:22:58.900 --> 00:23:02.520 But if you call it with the empty list, where it says a list of strings, it says, no, no, 00:23:02.520 --> 00:23:03.620 no, it can't be an empty list. 00:23:03.620 --> 00:23:05.860 It has to be a non-empty list of strings. 00:23:05.860 --> 00:23:09.960 So there's like some pretty crazy things that you can, can do here. 00:23:09.960 --> 00:23:11.200 yeah. 00:23:11.200 --> 00:23:16.040 Some other stuff you can check if you'd like, but yeah, it's, I wanted to read this, this 00:23:16.040 --> 00:23:19.460 introduction article here, which actually comes after all the examples. 00:23:19.920 --> 00:23:27.580 by the way, it also, in order to run this whole bunch of times, it took 33 microseconds, 00:23:27.580 --> 00:23:29.420 which is pretty incredible. 00:23:29.420 --> 00:23:36.020 The test, test this for like an array of tuples of arrays of what is that? 00:23:36.020 --> 00:23:38.180 A million, you know, 33 microseconds. 00:23:38.180 --> 00:23:39.260 So that's pretty fast actually. 00:23:39.260 --> 00:23:39.820 Yeah. 00:23:39.820 --> 00:23:44.760 You still want to like compare it like your entire, like some workflow compared to with 00:23:44.760 --> 00:23:45.220 or without. 00:23:45.220 --> 00:23:45.740 So. 00:23:45.740 --> 00:23:46.640 Yep. 00:23:46.640 --> 00:23:47.640 So let me read this. 00:23:47.640 --> 00:23:49.520 So if people are wondering, what the heck is this? 00:23:49.520 --> 00:23:55.560 Bear type brings Rust and C++ inspired zero cost abstractions into the lawless world of dynamic 00:23:55.560 --> 00:24:01.220 typing, dynamically typed Python by enforcing type safety at the granular level of functions 00:24:01.220 --> 00:24:04.800 and methods against type hints standardized by the Python community. 00:24:04.800 --> 00:24:09.340 And oh, one non amortized worst case time with negligible constant factors. 00:24:09.340 --> 00:24:10.160 How about that? 00:24:10.160 --> 00:24:12.720 So if anyone asks what bear type is, there's a good description. 00:24:12.720 --> 00:24:14.560 Yeah. 00:24:14.560 --> 00:24:16.560 Well, yeah, it's, it's pretty cool. 00:24:16.560 --> 00:24:19.200 And then there's a whole bunch of stuff about it, but anyway, that that's bear type. 00:24:19.200 --> 00:24:20.620 It looks pretty promising to me. 00:24:20.620 --> 00:24:25.860 Like the drawback of a lot of these think really is like, well, now you're doing a bunch of checking 00:24:25.860 --> 00:24:29.740 for every little function call and it's super slow, but if it's fast enough, that's, that's 00:24:29.740 --> 00:24:30.060 pretty cool. 00:24:30.060 --> 00:24:30.500 Yeah. 00:24:30.500 --> 00:24:32.740 So a couple of comments in the chat. 00:24:32.740 --> 00:24:39.600 Mike Felder doesn't Pydantic include call validators too. 00:24:39.600 --> 00:24:40.940 So I'm not sure how that relates. 00:24:40.940 --> 00:24:42.240 I don't know if that's out of beta. 00:24:42.240 --> 00:24:46.400 Last time I looked at it, it was still in like a testing phase. 00:24:46.400 --> 00:24:47.700 It may be out there. 00:24:47.700 --> 00:24:50.160 I mean, there's a ton of work that's happened on Pydantic. 00:24:50.160 --> 00:24:51.320 It's all been redone. 00:24:51.320 --> 00:24:53.100 So I don't know the status of that. 00:24:53.100 --> 00:24:53.820 Maybe Mike does. 00:24:53.820 --> 00:24:54.360 Okay. 00:24:54.500 --> 00:24:57.460 And then also, is there a mypy plugin that does that? 00:24:57.460 --> 00:25:01.500 I don't, I don't, I wasn't aware that mypy could be used at runtime, but. 00:25:01.500 --> 00:25:05.240 I wasn't aware mypy could be used at runtime either, but perhaps. 00:25:05.240 --> 00:25:06.080 Yeah. 00:25:06.080 --> 00:25:06.580 Anyway. 00:25:06.580 --> 00:25:10.300 But anyway, this, this looks pretty, you know, quite straightforward, pretty useful. 00:25:10.300 --> 00:25:14.300 You just do type ins, you put app bear type on it and it, it makes sure that it behaves. 00:25:14.300 --> 00:25:14.920 Yeah. 00:25:14.920 --> 00:25:19.420 So to do what you were looking at, sorry, to do where you might want to turn it off in production, 00:25:19.420 --> 00:25:21.400 but run it in testing, which is reasonable. 00:25:21.400 --> 00:25:23.860 I don't see any mechanism for that. 00:25:23.860 --> 00:25:24.520 There may be. 00:25:24.520 --> 00:25:25.000 Yeah. 00:25:25.000 --> 00:25:27.220 But it's a, it's a decorator mechanism. 00:25:27.220 --> 00:25:29.800 So you could, you could work around it if you needed to. 00:25:29.800 --> 00:25:35.260 Well, you could just write a decorator that looks whether that setting is on or off and 00:25:35.260 --> 00:25:39.200 either returns the bear type wrap thing or the direct function directly. 00:25:39.200 --> 00:25:43.940 And it would be like zero runtime cost once it's turned off because the function is replaced 00:25:43.940 --> 00:25:44.480 with itself. 00:25:44.480 --> 00:25:44.920 Yeah. 00:25:44.920 --> 00:25:47.140 Otherwise it's replaced by the bear type decorated one. 00:25:47.140 --> 00:25:47.380 Right. 00:25:47.420 --> 00:25:50.680 So you could, you might have to write like 10 lines of Python. 00:25:50.680 --> 00:25:51.320 Yeah. 00:25:51.320 --> 00:25:52.680 Then you've got that feature, right? 00:25:52.680 --> 00:25:57.180 The other thing is how much of your code are you really going to want to throw bear type 00:25:57.180 --> 00:25:58.920 decorators around all over the place? 00:25:58.920 --> 00:25:59.180 Yeah. 00:25:59.180 --> 00:26:00.200 That's a good point. 00:26:00.200 --> 00:26:01.520 Maybe just the boundary, right? 00:26:01.520 --> 00:26:01.940 Yeah. 00:26:01.940 --> 00:26:03.680 At the API level or something. 00:26:03.680 --> 00:26:03.820 Yeah. 00:26:03.820 --> 00:26:04.200 Exactly. 00:26:04.200 --> 00:26:04.900 Exactly. 00:26:04.900 --> 00:26:05.540 Yeah. 00:26:05.540 --> 00:26:06.280 Cool. 00:26:06.280 --> 00:26:06.620 Yep. 00:26:06.620 --> 00:26:07.560 Anyway, there it is. 00:26:07.560 --> 00:26:10.060 And I suppose that's it for all of our items. 00:26:10.060 --> 00:26:12.160 That's what we got lined up for you. 00:26:12.160 --> 00:26:12.760 Anything else? 00:26:12.760 --> 00:26:13.680 Some extras. 00:26:13.680 --> 00:26:14.260 I have. 00:26:14.260 --> 00:26:15.180 You want me to go first? 00:26:15.180 --> 00:26:15.840 You want to save yours? 00:26:15.840 --> 00:26:16.280 Yeah. 00:26:16.280 --> 00:26:17.200 You go first. 00:26:17.200 --> 00:26:17.700 All right. 00:26:17.700 --> 00:26:18.660 I already got my screen up anyway. 00:26:18.660 --> 00:26:19.180 Okay. 00:26:19.180 --> 00:26:26.780 So first of all, congratulations, Mike Falder, who is right here in the audience. 00:26:26.780 --> 00:26:27.260 Yeah. 00:26:27.260 --> 00:26:28.740 And I mispronounced his last name. 00:26:28.740 --> 00:26:29.020 Sorry. 00:26:29.020 --> 00:26:31.260 Hopefully I got it right. 00:26:31.260 --> 00:26:31.840 You did. 00:26:31.840 --> 00:26:32.620 I got it right. 00:26:32.620 --> 00:26:39.880 At Mike the man on Twitter is the new safety and security engineer for PyPI. 00:26:39.880 --> 00:26:41.220 That's awesome, Mike. 00:26:41.220 --> 00:26:42.060 Thank you so much. 00:26:42.060 --> 00:26:42.560 Cool. 00:26:42.680 --> 00:26:45.020 Clearly an area that needs lots of attention. 00:26:45.020 --> 00:26:47.440 So I just wanted to say welcome. 00:26:47.440 --> 00:26:49.260 Thanks for keeping us all safe out there. 00:26:49.260 --> 00:26:51.140 And excellent. 00:26:51.140 --> 00:26:51.660 Yeah. 00:26:51.660 --> 00:26:53.640 I got to hang out with Mike a lot at PyCon. 00:26:53.640 --> 00:26:55.160 So that's really pretty cool. 00:26:55.160 --> 00:26:55.980 Yeah. 00:26:55.980 --> 00:26:56.300 Thanks. 00:26:56.300 --> 00:26:56.640 Super cool. 00:26:56.640 --> 00:26:57.140 Super cool. 00:26:57.380 --> 00:27:00.700 And then a couple of quick announcements, two conferences for people. 00:27:00.700 --> 00:27:03.820 Packaging Con, follow up on all of your items, Brian. 00:27:03.820 --> 00:27:04.820 Packaging Con. 00:27:04.820 --> 00:27:05.400 Cool. 00:27:05.400 --> 00:27:07.820 Is happening fully online. 00:27:07.820 --> 00:27:08.760 No, hold on. 00:27:08.760 --> 00:27:08.960 No. 00:27:09.000 --> 00:27:10.740 It's happening in Berlin as hybrid. 00:27:10.740 --> 00:27:18.260 So it's in Berlin, October 26 to 28 for all things packaging, Python people, Rust people, 00:27:18.260 --> 00:27:18.760 et cetera. 00:27:18.760 --> 00:27:20.580 So check that out. 00:27:20.580 --> 00:27:24.660 And the Cloud Builders Python Conf is September 6, 2023. 00:27:24.660 --> 00:27:27.100 That's put together by a Ukrainian group. 00:27:27.100 --> 00:27:28.460 And it's just online. 00:27:28.460 --> 00:27:30.740 So people can check that out as well. 00:27:30.740 --> 00:27:34.220 And speakers, are they still have a call for proposals? 00:27:34.220 --> 00:27:35.820 Doesn't look like it. 00:27:35.820 --> 00:27:36.480 I think it's open. 00:27:36.480 --> 00:27:39.380 It's already all set for the agenda. 00:27:39.380 --> 00:27:40.680 So people can check that out. 00:27:40.680 --> 00:27:41.480 It should be fun. 00:27:41.480 --> 00:27:43.060 And on to your big news. 00:27:43.060 --> 00:27:43.660 Okay. 00:27:43.660 --> 00:27:48.580 Well, a couple, just a couple notes that I wanted to mention. 00:27:48.580 --> 00:27:54.080 The August release of Visual Studio Code has something I've been long awaiting. 00:27:54.080 --> 00:27:56.580 It's an error tolerant pytest discovery. 00:27:56.580 --> 00:27:58.220 So what does this mean? 00:27:58.220 --> 00:28:01.860 It means you've got, and there's like some comments down here. 00:28:01.860 --> 00:28:03.040 Oh, I went too far. 00:28:03.040 --> 00:28:05.360 You have to turn it on right now. 00:28:05.520 --> 00:28:06.980 But it's just in a setting. 00:28:06.980 --> 00:28:09.260 Apparently, some people have it on by default. 00:28:09.260 --> 00:28:11.020 Anyway, they should just turn it on. 00:28:11.020 --> 00:28:11.480 It's better. 00:28:11.480 --> 00:28:18.720 But the gist is, if you've got like errors in some of your code, it used to not. 00:28:18.720 --> 00:28:19.940 It used to just blow up. 00:28:19.940 --> 00:28:21.540 Like, let's say you've got a test suite. 00:28:21.540 --> 00:28:26.720 But you also have like some old junk tests off in a side directory that you don't use anymore. 00:28:26.960 --> 00:28:32.880 If they had import errors or syntax errors or whatever, it would just blow up the whole thing and you couldn't get any tests to import. 00:28:32.880 --> 00:28:39.240 Now, it's tolerant and it just turns off the, it doesn't, it doesn't import those tests that have import errors. 00:28:39.240 --> 00:28:40.000 That's great. 00:28:40.000 --> 00:28:41.500 So you can still run the rest of the suite. 00:28:41.760 --> 00:28:42.560 So that's good. 00:28:42.560 --> 00:28:45.080 Be kind of still kind of cool. 00:28:45.080 --> 00:28:45.920 There's a couple of things. 00:28:45.920 --> 00:28:51.000 Be kind of cool if it could tell you which ones have had errors instead of just making them disappear. 00:28:51.000 --> 00:28:51.740 So that'd be neat. 00:28:52.340 --> 00:28:55.700 The other thing is, guys, pytest isn't capitalized. 00:28:55.700 --> 00:28:59.480 So you've got to work on your capitalization, non-capitalization. 00:28:59.480 --> 00:29:01.920 But discovery probably should be. 00:29:01.920 --> 00:29:02.820 Oh, yeah. 00:29:02.820 --> 00:29:03.300 Oh, yeah. 00:29:03.300 --> 00:29:04.320 Discovery should be. 00:29:04.320 --> 00:29:04.880 Oh. 00:29:04.880 --> 00:29:05.760 That's all right. 00:29:05.760 --> 00:29:06.720 That's tough. 00:29:06.720 --> 00:29:07.240 Anyway. 00:29:07.240 --> 00:29:10.220 I always, I'm always unsure about my capitalization. 00:29:10.220 --> 00:29:13.020 It's so formal to capitalize everything. 00:29:13.020 --> 00:29:19.860 It's this time of year again, we got Python 3.12, release candidate 1. 00:29:20.200 --> 00:29:24.060 So we're in the release candidates for Python 3.12. 00:29:24.060 --> 00:29:24.800 It's pretty exciting. 00:29:24.800 --> 00:29:27.140 Release candidate is a big deal, though, right? 00:29:27.140 --> 00:29:31.520 It's, we think this is the final version unless there's something gone wrong. 00:29:31.520 --> 00:29:31.980 Yeah. 00:29:31.980 --> 00:29:34.060 It's right out of beta. 00:29:34.060 --> 00:29:44.940 So anyway, speaking of beta, the big news for today is that I've got a Python testing with pytest bundle course up. 00:29:44.940 --> 00:29:47.320 And I'm super excited about it. 00:29:47.320 --> 00:29:48.640 I'm working really hard. 00:29:48.980 --> 00:29:54.840 However, it is in pre-release, pre-release beta. 00:29:54.840 --> 00:29:55.360 I don't know. 00:29:55.360 --> 00:29:56.900 I made up something that. 00:29:56.900 --> 00:29:57.520 Early bird. 00:29:57.520 --> 00:29:58.720 Early bird sort of. 00:29:58.720 --> 00:30:00.240 Early beta bird. 00:30:00.240 --> 00:30:00.560 Yeah. 00:30:00.560 --> 00:30:02.280 So what is going on? 00:30:02.280 --> 00:30:07.040 So there's, in the end, it's going to be, actually, I wrote it. 00:30:07.160 --> 00:30:13.460 I included on here is a video that is got like, welcome to the pre-release beta. 00:30:13.460 --> 00:30:14.200 And what does that mean? 00:30:14.200 --> 00:30:14.640 Video. 00:30:14.640 --> 00:30:15.400 So you can watch that. 00:30:15.900 --> 00:30:21.260 The gist of it is, is the three sections of the book are going to go into three different courses. 00:30:21.260 --> 00:30:27.740 But the pre-release right now that's for sale is a bundle of all that will be all three. 00:30:28.540 --> 00:30:33.560 There's two chapters ready for, for the primary power for the first part. 00:30:33.560 --> 00:30:37.700 And, but I'm just going to chug along and people can jump in if they want. 00:30:37.700 --> 00:30:45.000 I'm, I'm doing it as a beta because the book itself really is better because of the beta program that I did when I was writing the book. 00:30:45.000 --> 00:30:54.180 And I'd love to have people come in and let me know where things need a little polish and we can, you know, we can fix it along the way. 00:30:54.180 --> 00:31:02.420 I also am setting up a job or not a job board, a discussion board for people to ask questions if they get stuck. 00:31:02.420 --> 00:31:08.920 I really want to make sure everybody's successful in getting, getting this up and running, getting up and running and py test quickly. 00:31:08.920 --> 00:31:11.560 So totally excited about getting this done. 00:31:11.560 --> 00:31:23.580 Oh, one more thing I set up, I just, just launched it last night, but, for Python bytes listeners, you can use the coupon code Python bytes with a Y. 00:31:23.580 --> 00:31:34.580 So, and, he, we'll just throw that in the show notes, use Python bytes, with a Y and you can get 20% discount now through the end of the 17th. 00:31:34.580 --> 00:31:36.440 So just a few days. 00:31:36.440 --> 00:31:39.240 but, that's enough time to grab it. 00:31:39.240 --> 00:31:39.880 So cool. 00:31:39.880 --> 00:31:40.260 Yeah. 00:31:40.260 --> 00:31:40.540 Awesome. 00:31:40.540 --> 00:31:41.520 Congrats on this, Brian. 00:31:41.520 --> 00:31:42.720 And this will be exciting. 00:31:42.720 --> 00:31:44.260 And I know it's a lot of work, so. 00:31:44.260 --> 00:31:45.960 Yeah. 00:31:45.960 --> 00:31:46.440 Good luck. 00:31:46.440 --> 00:31:46.980 Thanks. 00:31:46.980 --> 00:31:48.840 Yeah, absolutely. 00:31:48.840 --> 00:31:53.660 Oh, you know what else is a lot of work and ties back to my first item, learning JavaScript. 00:31:53.660 --> 00:31:54.800 Let's make that our joke. 00:31:54.800 --> 00:31:55.260 Okay. 00:31:55.260 --> 00:31:56.140 All right. 00:31:56.140 --> 00:31:57.800 So here's the text. 00:31:57.800 --> 00:32:03.780 It looks like a WhatsApp conversation that somebody got, unfortunately from their apartment manager. 00:32:03.780 --> 00:32:06.360 And of course it's addressed to Michael, which is extra funny. 00:32:06.360 --> 00:32:07.120 Hello, Michael. 00:32:07.320 --> 00:32:10.380 Your apartment has received the second complaint. 00:32:10.380 --> 00:32:12.940 noise from the apartment is the problem. 00:32:12.940 --> 00:32:13.860 The dog whines. 00:32:13.860 --> 00:32:16.700 Apparently you leave one home and the dog gets bored. 00:32:16.700 --> 00:32:18.420 Please address this. 00:32:18.420 --> 00:32:20.320 The response from Michael is hello. 00:32:20.320 --> 00:32:21.080 I don't have a dog. 00:32:21.080 --> 00:32:22.320 This is me learning JavaScript. 00:32:22.320 --> 00:32:25.320 Like screaming and yelling and kicking. 00:32:25.320 --> 00:32:27.760 Oh, a dog whines. 00:32:27.760 --> 00:32:28.200 Okay. 00:32:28.200 --> 00:32:29.440 Oh. 00:32:29.440 --> 00:32:31.780 Yeah. 00:32:31.780 --> 00:32:33.080 That's pretty good. 00:32:33.080 --> 00:32:34.020 That is pretty funny. 00:32:34.020 --> 00:32:35.440 It could be like learning all sorts of programs. 00:32:35.440 --> 00:32:37.000 It could be learning Python, but yeah. 00:32:37.000 --> 00:32:38.280 It feels a little extra special. 00:32:38.280 --> 00:32:39.420 A little extra special there. 00:32:39.780 --> 00:32:41.080 Have you got your web pack working? 00:32:41.080 --> 00:32:43.020 Have you got your requires working? 00:32:43.020 --> 00:32:46.580 have you got your transpiler working yet? 00:32:46.580 --> 00:32:49.940 Man, that was me with like trying to relearn CSS. 00:32:49.940 --> 00:32:56.040 so first time I learned CSS, we didn't have all these like pre compilers and stuff. 00:32:56.040 --> 00:32:59.160 so CSS is a completely different ball game now. 00:32:59.160 --> 00:32:59.480 So. 00:32:59.480 --> 00:33:00.160 Yeah. 00:33:00.160 --> 00:33:00.500 Yeah. 00:33:00.500 --> 00:33:02.080 Well, yeah, it's crazy stuff. 00:33:02.080 --> 00:33:02.900 Cool. 00:33:02.900 --> 00:33:04.880 Well, anyway, this is my joke for everyone. 00:33:04.880 --> 00:33:06.400 We've received a noise complaint. 00:33:06.400 --> 00:33:06.860 I'm sorry. 00:33:06.860 --> 00:33:07.860 I don't have a dog. 00:33:08.580 --> 00:33:09.020 Awesome. 00:33:09.020 --> 00:33:10.980 Well, it was a fun episode. 00:33:10.980 --> 00:33:11.620 Thanks again. 00:33:11.620 --> 00:33:12.880 Yeah, sure was. 00:33:12.880 --> 00:33:13.580 See you later.