Transcript #389: More OOP for Python?
Return to episode page view on github00:00 Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
00:04 This is episode 389, recorded June 24th. I'm Brian Okken.
00:09 And I'm Michael Kennedy.
00:11 This episode is brought to you by Scout APM.
00:13 Listen to their spot later in the show and check them out by going to the show notes and clicking it.
00:19 You can connect with us on Mastodon. We love hearing from you.
00:23 And if you're listening to this later, join us live every once in a while if you want.
00:30 Go to pythonbytes.fm/live to be part of the audience and it'll tell you when the next episode is.
00:36 And I'd like to say thank you to everybody that signed up for the mailing list to get our show notes.
00:42 It's nice to see that little creeping up in listeners.
00:47 And I actually find it quite handy to find those notes later on.
00:52 Absolutely. Brian, I would like to add, we're coming up on a milestone number there.
00:56 And I feel like we should probably do some kind of giveaway or some kind of contest.
01:01 And they'll probably happen in about the next month to six weeks.
01:04 So you got to be on the list to win the prize that we invent for the thing that we'll talk about later.
01:09 So sign up.
01:10 Yeah.
01:11 Go on by side of him.
01:12 Click on newsletter.
01:13 Put your info in.
01:14 All right.
01:14 Well, why don't you kick us off with it's a nice sunny day.
01:18 Maybe some sort of solar topic.
01:20 Yes, let's do it.
01:22 Let's do it.
01:22 How about this, Brian?
01:24 Let's talk about Solera.
01:26 And this one comes to us as a recommendation from a listener.
01:29 So thank you to Florian for sending this in.
01:32 Solera is a...
01:34 Solera?
01:34 Solera?
01:35 I don't know.
01:35 Tomato or tomato?
01:36 Solera is a pure Python framework, but in React style.
01:41 So it is a sort of rapid application development, somewhat data science-y focused front-end framework
01:48 or framework for building front-end UIs that's like React that allows you to write better Jupyter
01:55 and web apps.
01:57 So it does this by basically integrating IPy widgets and other types of React-based APIs,
02:04 programmable, like code, not APIs you call, on top of IPython widgets.
02:09 So that's super cool.
02:11 It can either be stuff that runs inside notebooks that makes them better interactive things,
02:15 or it can just be standalone web apps, like FastAPI or stuff like that.
02:21 Yeah?
02:21 Pretty neat, huh?
02:22 Yeah.
02:23 So we always need more UI frameworks than Python, I believe.
02:28 I would put this if I was considering Streamlit or Dash or something along those lines.
02:34 It's kind of in that realm, okay?
02:35 So let's see.
02:37 It talks about the benefits of putting things together.
02:39 But the most important thing I would recommend to you is probably check out their examples to start.
02:45 So let's check out their examples.
02:48 So in this area, we've got a whole bunch of different examples that don't want to scroll.
02:53 Why won't you scroll?
02:54 Hold on.
02:55 There we go.
02:55 Now it's scrolls.
02:56 Yay, browser.
02:57 So let's pick one of these.
02:59 Let's go to the full screen ones.
03:00 These are fun.
03:01 Jesus, really doesn't like to scroll, does it?
03:04 Full screen.
03:05 Okay, so we've got different ones here.
03:07 You can just pull these up.
03:07 And let's just say the scatter one's kind of interesting.
03:11 Check this out, Brad.
03:12 This is how this works.
03:13 So you take your iPython widgets, your notebook-like stuff.
03:18 And look what you would see on the screen if you load this up.
03:21 It's like a full UI.
03:23 It fills the screen here, right?
03:26 And you can either upload a data set and figure out, I don't know how to figure out what the
03:29 data set's supposed to be, but probably a CSV or something.
03:32 And then you can also just click, show me the sample data.
03:34 And check it out.
03:35 You get this cool interactive, probably plotly.
03:38 Yes, plotly.
03:40 UI here.
03:41 And I can change the size of all these things that it works on.
03:45 I can say, I would like to see, this talks about like GDP, life expectancy by country.
03:50 So I can say, I want to see the life expectancy by country.
03:53 And pull that up.
03:55 Continent, rather, I think is how they have data.
03:58 Where is this?
03:59 It was working just a minute ago.
04:00 Why is this not running for me?
04:02 Maybe I made the size too weird for it.
04:03 Don't know.
04:04 Let's go.
04:06 Country.
04:07 Nah, I guess I'm picking the wrong thing.
04:10 That's just the live demo curse.
04:11 It just won't work.
04:12 It totally is.
04:13 I don't know why it's not working.
04:14 Anyway, there we go.
04:15 I just have to reverse it.
04:16 There we are.
04:17 This is looking good.
04:17 So you can say, show me the life expectancy by country.
04:23 And then you get all these really interesting interactive bits.
04:26 You can resize it.
04:27 So this is all a super easy UI to build, Brian, with this UI framework.
04:32 That's pretty cool.
04:33 And if you go back and look at the example, they'll show you like one of the cells in a
04:38 Jupyter notebook can just be this graph here.
04:41 And it has a full screen option or it can just be like the output of a cell.
04:45 It's one of these interactive apps.
04:47 Oh, neat.
04:47 How wild is that, huh?
04:48 Isn't that crazy?
04:49 Yeah.
04:50 And then you can also go and see, you know, what does a tutorial look like?
04:54 Somewhere.
04:56 I gotta go to get started.
04:58 Quick start.
04:59 So if you go to the quick start, it'll show you basically how to program this stuff.
05:04 And it's super easy.
05:05 You just put a decorator, say this is a component, and it shows up in your page.
05:10 It's really focused on building these little reasonable and composable components.
05:14 So it's a little bit like shiny, actually, I think, actually.
05:17 So anyway, super cool way to build these interactive dashboards and stuff that's more than just a picture,
05:23 but a thing you can actually play with and publish to the web.
05:27 Yeah, especially, I love stuff like this, like, especially if you don't really know how you want to look at the data yet.
05:32 So you can give people lots of options.
05:35 Absolutely.
05:36 And I don't see a price.
05:39 All I see is Staris on GitHub.
05:41 So I think it's just an open source project that you can use for your stuff, not a commercial thing, from what I can tell.
05:47 So one of the things, I was looking at this the other day, and I don't know if you came across an answer to this question,
05:53 but it said a pure Python React-style framework for scaling Jupyter and web apps.
06:00 The and is, like, I was a little bit confused.
06:04 Do I have to be a Jupyter-type programmer to do this, or do you know if I can?
06:09 No.
06:09 If you want to use FastAPI, it can.
06:12 And there's a thing called, what do they call it?
06:15 A Solaris server or something like that.
06:19 So you can run that, and it says, look, it'll run with FastAPI, Starlet, Flask, and so on.
06:23 Okay.
06:24 And I imagine you just create, just basically serve up some common template that, like, starts it all, you know, those kind of things.
06:31 The other thing that's worth pointing out in this whole discussion is, it says built on top of React-ton.
06:36 And React-ton is this interesting project here.
06:40 It says it's like React.
06:42 Yeah, it is.
06:44 It's a really good logo.
06:46 It's a Python logo as the nucleus of an atom, and then a bunch of little small Python logos circling it like electrons.
06:54 That's good.
06:55 So this basically lets you create code for IPython widgets that is in the style of React.
07:01 So if you go down here, you can create, for example, a component, which is a clickable button.
07:08 And you basically initialize the state, and then you write the handler.
07:13 And just like the handful of lines of code.
07:15 Yeah.
07:16 Yeah.
07:16 Yeah, it's pretty neat.
07:17 And so that's what this thing is all about, is creating these little widget-type things or components, and then building up your UI out of it.
07:23 So I say, certainly worth checking out.
07:26 I kind of want to just do one of those, like, just a button that just tells you how many times you've clicked it.
07:31 Exactly.
07:34 I'm not going to do anything.
07:36 After it gets past 100, it'll be like, what are you doing in your life?
07:41 Leave and go do something else.
07:42 Stop clicking me.
07:43 Yeah.
07:44 All right.
07:45 Yeah, people check that out.
07:46 Thanks, Florian.
07:46 Next up, I wanted to talk about coverage a little bit.
07:51 I think?
07:52 No, I'm on the wrong page.
07:54 I do want to talk about coverage.
07:55 So Ned Batchelder wrote an article called Coverage at a Crossroads.
08:01 And so there's a couple things I wanted to point out about this.
08:07 So the gist of it is, Ned wants to make coverage.py faster.
08:18 And one of the issues is with the way coverage is written right now and the way it's composed.
08:23 So he starts the conversation discussing really how coverage works.
08:28 And that's the part where I really like, even if you don't care whether coverage is fast or not, this is a nice, fun article to realize how coverage works.
08:37 And so coverage uses a thing called a trace function.
08:40 So it takes your code and adds these trace functions to every line so that coverage can know when any line gets hit.
08:47 And then coverage also does branch coverage.
08:49 So coverage does branch coverage with allowing a thing called the arcs.
08:54 So it generates these four lines that look like branches, these arcs of like, it could go like your line, you could go from line one to line two or line two to line three, things like that.
09:06 And so it keeps track of all that.
09:08 And the reason why things could be faster is because like, let's say you hit line two already.
09:15 You don't have to, and there's no branches in there or anything.
09:18 It's just a line of code.
09:19 You wouldn't need to actually hit the trace function every time you hit that, but there's no way to take it out.
09:27 So there's some ideas around making it faster.
09:31 And SlipCover, for instance, has a bunch of ways.
09:34 So he uses a bytecode thing that there's a discussion around SlipCover as a different coverage tool.
09:41 There's also discussion around SysDop monitoring that came in in Python 3.12.
09:46 And with SysDop monitoring, you can do something like a trace function, but it's something that you can take away later.
09:53 So the idea, like for line coverage, this would work just great.
09:57 So you could just say with SysDop monitoring every time, if I hit this line, great, now I can take that out so I don't have to worry about that line ever again.
10:07 But there's some discussion that Ned has around how do you deal with branching for that.
10:16 And it's an interesting take on kind of an interesting idea.
10:21 There's an interesting problem set for how to deal with it, kind of like maybe ARCs aren't the right way to do it.
10:28 Maybe there's some other way to deal with branch coverage.
10:32 And it's not trivial because there's an example of a try finally block with a return statement happening in the try.
10:41 So you don't necessarily hit – you always will hit the finally even with the return, but you don't know if you'll hit the line after.
10:51 You know, you'd have to look at the code.
10:53 But really fun discussion.
10:56 There's a call out of where if you want to get involved, you'd like to offer some solutions or just help with the discussion.
11:02 There's that too.
11:03 But even if you're not going to help, I think it's a cool discussion of how coverage works.
11:10 And I just wanted to thank Ned for putting time and effort into making sure coverage is an awesome tool.
11:16 So thanks, Ned.
11:17 Yeah, that's pretty excellent.
11:18 And of course, there's going to be functions and branches of execution that are in some kind of tight loop and run a million times.
11:26 But after the third time, you've already realized it's 100% covered.
11:31 So if you could just – because running with coverage and stuff like that, all this profiling and code coverage stuff puts a serious hurting on the performance.
11:39 So if you could say, all right, that part's done 100%, stop slowing it down, that'd be cool.
11:44 Yeah, I did like this cool idea of – with the other ones of creating like adding no-op statements in just so that for branches,
11:54 so that you just like check to see, you know, if I hit that, then that branch was taken.
12:00 That's kind of a neat idea.
12:01 You could, you know, add these extra little hooks.
12:03 But anyway, cool.
12:05 Awesome, awesome.
12:07 Up next, thank you to Scout APM.
12:11 Let me tell you real quick about Scout APM.
12:15 They're big supporters of Python Bytes, so we appreciate that very much.
12:19 So if you are tired of spending hours trying to find the root cause of issues impacting your performance,
12:25 then you owe it to yourself to check out Scout APM.
12:28 They're a leading Python application performance monitoring tool, APM, that helps you identify and solve performance abnormalities faster and easier.
12:37 Scout APM ties bottlenecks such as memory leaks, slow database queries, background jobs,
12:42 and the dreaded N plus one queries that you can end up if you do lazy loading in your ORM.
12:48 And then you say, oh, no, why is it so slow?
12:50 Why are you doing 200 database queries for what should be one?
12:53 So you can find out things like that.
12:54 And it links it back directly to source code so you can spend less time in the debugger and healing logs and just finding the problems and moving on.
13:02 And you'll love it because it's built for developers by developers.
13:04 It makes it easy to get set up.
13:06 Seriously, you can do it in less than four minutes.
13:09 So that's awesome.
13:09 And the best part is the pricing is straightforward.
13:12 You only pay for the data that you use with no hidden overage fees or per seat pricing.
13:19 And I just learned this, Brian.
13:20 They also have they provide the pro version for free to all open source projects.
13:26 So if you're an open source maintainer and you want to have Scout APM for that project, just shoot them a message or something on their pricing page about that.
13:33 So you can start your free trial and get instant insights today.
13:37 Visit by thembytes.fm slash Scout.
13:40 The link is in your podcast player show notes as well.
13:42 And please use that link.
13:43 Don't just search for them because otherwise they don't think you came from us.
13:47 And then they'd stop supporting the show.
13:49 So please use our link by thembytes.fm slash Scout.
13:51 Check them out.
13:52 It really supports the show.
13:54 This one, Brian, comes to us from another Brian.
13:58 Okay.
13:58 Way in the past, though.
13:59 This is Brian Skin that back in January said, hey, guess what?
14:04 Pep 698 has been accepted.
14:07 How awesome is that?
14:08 And I haven't, it hasn't bubbled to the top of my list until now.
14:12 But I think it's, we're talking about this is in Python 312.
14:16 And yeah, let's, let's check it out.
14:19 So if we go over to the pep, it is an override decorator for static typing.
14:24 So, you know, some languages, C#, I think C++, but it's been a while since I messed with it.
14:30 You know, have explicit override keywords and virtual methods.
14:34 I know C++ has virtual methods.
14:36 I just don't know if you indicate that you're overriding it.
14:38 Tell me, Brian, do you use the override keyword?
14:40 Or do you just, do you just write the function?
14:42 You just, just write it.
14:44 Yeah, that's what I thought.
14:45 Yeah.
14:45 Yeah.
14:46 And in C#, you actually say there's a virtual function in the base class, which is intended to have a potential people overriding.
14:52 And then in the, the derived classes, you say override instead of virtual to indicate that you have to say that right to say that you're, you're replacing this behavior.
15:01 And you might need to call the base class version and all that kind of stuff.
15:04 Well, basically Python gets that if you want it as a lot of things with typing, it's multiple, it's optional and multiple ways.
15:12 So let's jump over.
15:14 If you scroll down, it's kind of weird to me.
15:16 The PEP says this PEP is here for historical reasons.
15:19 It's now part of Python.
15:21 So please see override.
15:24 When you click it though, it doesn't take you to the Python documentation.
15:26 It takes you a separate typing documentation for Python, but is also in the Python documentation.
15:32 Interesting.
15:33 Which one wins?
15:34 I don't know, but whatever.
15:35 The example here in the link from the PEP is super clear.
15:38 So you had a parent class and you don't say virtual because we don't have that, but you can say at override.
15:45 So the parent class, the base class has a foo function that takes no parameters and returns an integer.
15:52 I'd hear you in the child class, you say override and then as a decorator and then foo, same signature.
15:58 And if you were to say override something that didn't exist, type checking will say there's no signature.
16:04 Your intention is to override this thing, but it doesn't exist.
16:08 Maybe, maybe you meant to type.
16:10 I don't like these examples, but this is what's written here.
16:13 So here we go.
16:13 You overrode foo because that existed, but you tried to override baz, but it's bar and you misspelled it or something like that.
16:23 Now, I don't know what happens if you mismatch the parameters, but you get the name right.
16:28 You know what I mean?
16:28 Like I'm overriding.
16:29 It takes two parameters.
16:30 Like, no, it takes one.
16:31 I don't know.
16:32 I have to test that out.
16:33 But anyway, if you want to have a little bit more validation in your Python typing for your classes and your inheritance, check this out.
16:44 It's part of Python.
16:45 It's nothing special that you add.
16:47 It only executes at definition time for the class.
16:51 So it's not like a runtime type thing.
16:53 So it should be low overhead.
16:55 Yeah.
16:55 Pretty neat.
16:56 Why not use it, right?
16:56 Yeah.
16:57 Low overhead.
16:59 High override.
17:00 High override.
17:01 Low overhead.
17:02 That's right.
17:02 There you go.
17:03 All right.
17:03 Well, thanks, Brian Skin, for sending this in.
17:05 And yeah, interesting.
17:07 Cool.
17:08 One of the other things that's neat is speeding up Python bits.
17:16 And so there's kind of a neat article called from Gage.
17:22 Oh, that must be the group that makes this stuff.
17:25 Anyway, called Parsing Python ASTs 20 Times Faster with Rust.
17:30 So this article is talking about speeding up a tool called TAC.
17:36 Now, TAC is a CLI.
17:39 It says it's a CLI tool that lets you define and enforce import boundaries between Python modules in your project.
17:45 Yeah.
17:45 Remember, I talked about that a few weeks ago.
17:47 Yep.
17:47 Actually, right?
17:48 Yeah.
17:48 Episode 384, you talked about it.
17:50 So yeah, that was just May 21st, just a couple of months ago, or last month.
17:56 Nice.
17:57 Nice.
17:57 Anyway, at first, I'm like, okay, you sped up with Rust.
18:02 We're kind of hearing that.
18:04 Why I'm calling this out, though, is not just that TAC seems cool, is that I really liked the methodology that they're talking through here.
18:14 So they talk about not just how they made it faster, but the process they went through to figure out which parts.
18:20 So they used profiling, but in specific, I think they used a tool called PySpy and SpeedScope to visualize and get flame graphs for performance.
18:35 Interesting.
18:36 I've not heard of either of those.
18:37 I have not, or maybe I have, but we cover a lot of tools, man.
18:42 Anyway, these look slick, but the output of it showed that there was roughly 90% of the total time was taken by a function called get project imports.
18:55 And in that, it spent about two-thirds of the time parsing the ASTs and the remaining one-third traversing them.
19:02 So some great information and some great examples of instead of trying to just throw Rust at it to speed things up or even just using Python to optimizing your own Python,
19:15 taking a look at exactly what you're doing and only speeding up the little bits that are slow, which is a – I love that aspect of this.
19:25 So, okay, so they took those bits.
19:28 Also, went by and there's a discussion of why the AST parsing was slow anyway because that should have been some C code as well.
19:40 But they – there's a little bit of a deep dive into there, but then they jumped into just rewriting it in Rust.
19:50 And then this – we've covered these tools before using PyO3 and Maturin to help get – quickly develop some Rust for a couple functions.
20:03 And, yeah, so that was it.
20:06 And it, like, went from – the example they had was a code base – it was a common code base.
20:12 So, which was it – the Sentry code base, about 3,000 lines of Python files that took, like, 10 seconds to test.
20:21 And with this speed up, it dropped it down to one second.
20:25 So, yeah, 20 – that seems like a pretty fast speed up.
20:29 So, nice.
20:30 Yeah.
20:30 Yeah, it's real nice.
20:32 Also, just kind of a great user example and a short write-up on using these – using profiling to really look at where your bottlenecks are and then maybe throwing Rust at it there.
20:44 Yeah, and it looks like they just basically re-implemented that one function in Rust and then just used it as a dependency, right, with their PyO3 extension.
20:54 Yeah, so I totally want to try that.
20:56 Like, just – that would be a great way to get into Rust a little bit is to just not try to make a Rust application but just replacing, like, one function or something.
21:06 This one algorithm is called a ton of times.
21:09 It's super slow, relatively.
21:10 It's where we spend all our time.
21:12 But it's not that big, right?
21:13 Like, we could write it, probably figure it out in a day or two in Rust, and then off you go.
21:17 Yeah, I don't need to learn all the Rust.
21:19 I just need to make this thing faster.
21:21 Tell me how to do a for loop in Rust.
21:23 Tell me.
21:23 Okay.
21:23 Well, tell me, Brian, do you got extras?
21:27 Do I have extras?
21:29 Let me check.
21:30 Yeah, I do.
21:31 Last – when was it?
21:33 Let's go ahead.
21:35 Episode 388.
21:37 That was just last week, wasn't it?
21:38 It was last week where we talked about not deleting all the repos.
21:42 Yeah.
21:43 Well, one of the things I talked about was – what did I talk about?
21:47 I talked about import by string with packageutil.resolve name.
21:53 Bad on me for not doing my homework a little bit.
21:56 Brett Cannon notes that discussions around this are maybe not really great things because packageutil is deprecated or it's going to be or something.
22:09 So, Brett's recommending not using packageutil.
22:12 Just FYI.
22:13 If it doesn't give you a deprecation warning now, it will someday.
22:17 Don't go that way.
22:19 Okay.
22:19 Next up, really quickly, kind of a fun thing.
22:23 At the Python Language Summit, there was a discussion, should Python adopt calendar versioning?
22:32 And this kind of fun discussion.
22:35 So, we have like Python 3.12 right now.
22:39 Should somehow it be like Cal versioning?
22:43 And if we went to Cal versioning, what would it be?
22:45 And a fun – I think it was Carol Willing.
22:50 Yeah, Carol Willing brought up that we want to at least keep our current versioning through 3.14 because then it would be the Pi version and we can't –
23:00 Yes.
23:00 We've got to do 3.14 now.
23:02 Yeah.
23:03 So, a lot of this boils into a PEP 2026, which is also nice numbering because the shout-out of 2026 is when we would switch.
23:16 So, the idea would be what we've got – oh, there's a table here.
23:22 3.14, no change.
23:25 That comes out in 2025 if we go to this.
23:28 And instead of 3.15, we just make the 2026 version 3.26.
23:33 No.
23:34 Which would – We're going to end up with a year 3K problem.
23:40 That's – okay.
23:41 But how – that's like 75 years in the future that we have to care about that.
23:46 I guess they could put a 1.26.
23:48 Then it'll be 1,000 years.
23:50 It probably doesn't matter at that point.
23:51 Oh, yeah.
23:52 We can add it.
23:54 Yeah.
23:54 So, I think we're okay.
23:57 Well, actually, I'm not sure.
23:58 That would be weird, wouldn't it?
24:00 I don't know.
24:01 You could have 126.
24:02 I think you can get to year 2,999 without going too bizarrely out of secrets.
24:08 Yeah.
24:08 Maybe we're ready for Python 4 by then.
24:11 No.
24:12 We're not ready.
24:14 Too soon.
24:15 Too soon.
24:16 So, what do you think of this?
24:18 Should we recover?
24:19 It's a little weird to me.
24:21 Why not just 3.2026, 3.2027?
24:25 Because to me, this doesn't communicate calendar versioning.
24:30 We already have calendar versioning if you don't care about what the number is because it's yearly release cycles.
24:35 Right?
24:35 3.12 means 2024.
24:38 3.13 means 2025.
24:41 And so, if you're not using the calendar numbers, I know 26 is closer to 2026 than 15, but there's still, to me, it's like, well, 16, 27.
24:51 I don't know.
24:51 It's just, like, here's the next year's version.
24:53 Yeah.
24:55 Okay.
24:55 I'm all for it.
24:56 I think we should switch because I think that since we've gone to a one-year release cycle anyway, why not somehow encode that in the number?
25:06 I totally agree with that.
25:07 I agree with that.
25:08 I just, my vote's for 3.2026, like most calendar versioning things.
25:14 Oh, yeah.
25:14 Just do four digits?
25:15 Yeah, exactly.
25:16 That's all I'm saying.
25:17 It's just put four digits so it really is the year on the end.
25:19 And it's really clear that it means the year.
25:21 You don't have to know the code.
25:22 That's all I'm saying.
25:24 But I'm also with Carol on leaving 3.14.
25:29 Yeah.
25:30 I mean, there's nothing saying, since it's bigger, there's nothing saying we could go to two digits and then at some point go, you know, let's just throw four digits in there.
25:38 Yeah.
25:38 Anyway.
25:39 Okay.
25:40 Last thing I want to, last extra is Brett Cannon wrote an article called Saying Thanks to Open Source Maintainers.
25:49 I just want to shout out, this is a really good idea.
25:51 Quickly, what are your ideas?
25:54 First of all, just be nice to the maintainers.
25:57 This is great advice.
25:59 If you disagree with something, be polite, be nice.
26:05 It's good.
26:05 Great advice.
26:06 Start with be nice.
26:07 Be an advocate.
26:08 You don't have to actually thank him directly, but you could advocate for the thing.
26:12 So Brett's involvement with Bioproject.toml, he sees other people promoting it, makes him feel good.
26:17 It's a good thing.
26:19 Produce your own open source code because maybe some of the maintainer might use your stuff now.
26:25 And then actually say thanks.
26:26 Nothing wrong with saying thanks to people.
26:29 And then there's financial support, which is good for some projects that have open source.
26:35 You know, ways to help fund the maintainers.
26:37 Those are good, too.
26:38 But you don't have to fund them.
26:39 You can just be nice to them.
26:41 Say thanks.
26:41 Advocate their thing.
26:42 That's good.
26:44 So in that end, I kind of always forget that Brett was involved with PyProject.toml.
26:51 And we might not be using it as we are today without Brett.
26:54 So thank you, Brett.
26:55 I love PyProject.toml.
26:56 I promote it and encourage everybody to use it.
27:00 Awesome.
27:01 Yeah.
27:01 Thanks, Brett.
27:02 Thanks, everyone.
27:02 There's a lot of people I have to thank in this community for this kind of stuff.
27:05 Yeah.
27:06 Do you have any extras?
27:07 I do.
27:08 Let us check them out.
27:11 I think only one extra.
27:12 Extra.
27:13 And that is last week I talked about the Shiny for Python Reactive Web Dashboard with Shiny,
27:18 that course over at Talk Python.
27:21 I said it was going to be available soon.
27:23 It is now available 100%.
27:25 You can go sign up for it and take that course.
27:27 The course is completely free.
27:29 No strings attached.
27:31 So just click the link and take the course if you want to learn about building interactive dashboards.
27:36 A little bit actually like the Solara stuff, but more full-featured, I suppose.
27:40 And a little more packaged, a little more like Streamlit in that sense.
27:44 And then also I talked about working with PyCharm to get people six months of PyCharm Pro for free,
27:51 as long as you don't already have an account that would have to renew.
27:55 With this course, you could just go to your account page after signing up for this and get that as well.
28:00 So two extras on one tab.
28:03 How about that?
28:03 Nice.
28:04 Yeah.
28:04 All right.
28:05 Brian.
28:06 I need you to put yourself in like a calm and centered place for what is coming next.
28:11 Okay?
28:11 Are you ready?
28:12 This has been recommended to us.
28:15 Oh, my gosh.
28:16 Who sent it in?
28:17 I'm so sorry if I don't have the name here.
28:18 I don't.
28:19 Cohen, I believe it was.
28:21 If I got it wrong, I'll correct it next time.
28:23 This is the Tao of Programming.
28:26 This is a big, big book.
28:27 This is a big, long book here that covers many things.
28:31 But I will, because we may come back to this, right?
28:34 Okay.
28:34 But I want to start with book one, The Silent Void, and just read you a few bits of it.
28:39 And if you visit this webpage, folks, this is best viewed in Netscape Navigator 4.0 or older.
28:47 Because it's got like the digital noise background and all sorts of like, whoever thought like this arts and craft paper was the proper background for reading.
28:57 But here we are.
28:59 Oh, and it also has a frame.
29:00 There's a frame inside of it.
29:01 So it's just missing the blink tag.
29:03 Nonetheless, here we go.
29:04 Here is the introduction for the chapter.
29:06 Thus spake the master programmer.
29:09 When you have learned to snatch the error code from the trap frame, it will be your time.
29:13 It will be time for you to leave.
29:15 So let me just read you a couple little sections from this.
29:18 1.1.
29:19 Something mysterious is formed.
29:21 Born in the silent void.
29:22 Waiting alone and unmoving, it is at once still and yet in constant motion.
29:28 It is the source of all programs.
29:29 I do not know its name.
29:31 So I will call it the Tau of programming.
29:33 If the Tau is great, the operating system is great.
29:36 If the operating system is great, the compiler is great.
29:39 If the compiler is great, then the application is great.
29:42 The user is pleased and there is harmony in the world.
29:45 The Tau of programming flows far and returns on the wind of morning.
29:49 Oh dear.
29:50 I think it's a little easy.
29:53 This one's good, Ali.
29:55 This is one too.
29:56 This is the last one.
29:57 The Tau gave birth to machine language.
29:59 Machine language gave birth to the assembler.
30:02 The assembler gave birth to the compiler.
30:04 Now there are 10,000 languages.
30:05 Each language has its purpose, however humble.
30:08 Each language expresses the yin and the yang of software.
30:11 Each language has its place within the Tau.
30:14 But do not program in Cobalt if you can avoid it.
30:16 And Fortran and Burl.
30:20 Exactly.
30:20 Anyway, this goes on and on.
30:22 There's books of this stuff.
30:24 People check it out.
30:25 It's fun.
30:25 Nine books.
30:27 Exactly.
30:27 Dear.
30:29 Well, that's the joke for today.
30:33 If you will.
30:34 It's the entertainment segment, Liz.
30:36 I'm not sure it's a joke.
30:36 Yeah.
30:37 No, it's good.
30:39 I like it.
30:39 It's the meditation section, Brian.
30:42 All right.
30:44 So with that, I'd like to encourage everyone out there to send us good programming jokes because we're running dry.
30:51 No, that was good.
30:54 But also, yeah, I always love good programming jokes and dad jokes all together.
30:59 So keep them coming.
31:00 Yeah, they're always good.
31:01 As always, really enjoyed talking with you.
31:05 Enjoy talking with everybody in the community.
31:08 And yeah, keep on going and having fun.