Transcript #296: pip: Constrain your excitement
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:05 This is episode 296, recorded August 9th, 2022.
00:09 I'm Michael Kennedy.
00:11 And I'm Brian Okken.
00:12 Hey Brian. We have a new sponsor.
00:14 I just want to say thank you to Mozilla and the IRL podcast for sponsoring the show.
00:19 Check them out at pythonbytes.fm/irl.
00:22 More on that later.
00:23 For now, I want to hear what you've discovered to share with us.
00:25 Can you constrain your excitement?
00:27 >> Yeah. I want to talk about pip constraints.
00:31 I think I knew about pip constraints, but I forgot about them.
00:36 But there's an article called pip Constraints Files by somebody named Luminousman.
00:44 They're neat. I was just using pip requirements.in file recently in a course that I'm taking.
00:56 And I like using requirements.in to generate my requirements.txt file.
01:02 But there's, and then there's, yeah, anyway, that uses pip tools, so you have to get pip tools.
01:09 But, so there's that, and then there's also pinning.
01:11 So especially with applications, we see it more in applications, less in libraries of pinning the application.
01:19 But you can, even in libraries, there's regularly sort of constraints around stuff to say, hey, for this library, I need this range of versions, or it has to be greater than this or something, because I'm depending.
01:33 And that's fine.
01:33 But this is a way to say not what libraries I want to use, but if I use a library, which version?
01:43 Or constraint on the version without saying I want the library.
01:47 And actually, in the pip documentation, it says constraint files are requirement files that only control which version, not whether or not it's installed.
01:57 So how would you use this?
01:58 So this article talks about it and it basically says, you use it normally pip install requirements.txt, but you might have, if you do a freeze for instance or something, or you just pin everything, you might have all of the versions.
02:14 But you might only want constraints on one of them.
02:19 Say, let's say you're including pandas, but you want a certain version of pandas or you want a certain version of NumPy even though pandas requires NumPy or something like that.
02:29 You can have a constraints file that lists, this just looks like a pip freeze file, but you can put like less than or less than equal if you want, and you don't have to have everything.
02:41 So you could just pin one of the things.
02:43 And that way, like let's say you were doing pandas and you wanted to constrain NumPy to be a certain version of NumPy.
02:49 You can do that with a constraints file and not have to specify everything, just have it be separate.
02:55 And the article talks about actually just sticking the constraints, specifying your constraint file within the requirements file, and that way they're separate.
03:05 And I was thinking about that, and that's an interesting thing to say, the dependencies of my application don't change, but the constraints might because of testing or whatever.
03:15 And this separating of these two files would help with, like, you know, when you have the two files version control, you've changed your constraints, but you haven't changed really what you're depending on just the versions of those. So it's kind of a neat to have that separate possibility.
03:29 >>Yeah, so for people who are listening, literally the first line of the requirements.txt file is --constraint constraints.txt, which I'd never considered doing that. That's interesting.
03:39 >>And then one of the things I thought is, but I'm not, and this works if you're handwriting your requirements file, but what if you're not? What if you're using requirements.in instead.
03:52 This article doesn't go into it, but I tried just instead of putting that constraint thing in a requirements.txt file, putting it in a requirements.in and using pip compile to generate it.
04:05 The pip compile seems to also watch the look at this.
04:09 This constraint works for pip compile as well.
04:13 >> Okay. That's cool.
04:14 >> Yeah. A neat thing to check out.
04:18 The usage of it's pretty easy.
04:21 Pinning your requirements is good, but don't pin them too tight, especially for libraries and then for applications.
04:30 I like this because there's a lot of times where I know there's a bug in something, or I've heard about it, or I haven't gotten around to fixing my code to deal with the new version yet, so I'm going to pin something.
04:43 I don't necessarily need to pin everything, I just need to pin certain parts of it.
04:47 >> I like this.
04:50 Just also a little bit of a sidebar with the pip compile from pip tools.
04:54 You give it the in file and it generates the TXT file and it basically obliterates the TXT file, whatever is there previously.
05:02 >> Yeah.
05:02 >> That can be a hassle, especially if you want to have a requirements.dev, and then a production requirements.
05:10 If you install the dev one, you want to also pick up like a -r on the main ones.
05:16 And the pip-tools blows that away.
05:17 So what I ended up doing a lot for my workflows is having pip-tools generate some base TXT file and then having like requirements.txt just have a -r requirements production.
05:29 And then the dev have -r requirements.txt, you know, prod, like sort of like put those commands just in real simple and have it actually generate a separate file.
05:39 So it kind of makes it a little bit messy, but it gives you lots of flexibility.
05:42 >> Cool. Yeah. I like to see that written up. That's neat.
05:45 >> Yeah. Maybe I should actually blog something in the last three years.
05:49 >> Blog.
05:50 >> Yeah. What is that? Is that with words?
05:52 Written words, not spoken words.
05:54 Pamphlet on the audience says, "Does it take over requirements like if pip would resolve NumPy to 1.19 and you say at 120?" It sounds to me like it does, but what do you think, Brian?
06:04 >> Well, I tried it with Typer.
06:07 So I know Typer pulls in click, for instance, and they're both command line things.
06:13 And so then I said, okay, well, Typer has a broad range of click things that it can do.
06:20 And if I constrain click to be a lower number, will it work?
06:24 And I blew everything away and tried it again.
06:26 And sure enough, it did.
06:28 It like add those extra constraints on top of even, like, so I was only declaring Typer, but Typer was specifying click, and I could specify which version of Click I wanted.
06:38 >> Yeah, this is cool.
06:39 >> Yeah. I guess adding one more complexity to your packaging workflow.
06:47 >> Exactly.
06:48 >> But useful if you need it.
06:49 >> Flexibility.
06:49 >> Yeah, flexibility.
06:50 >> Good flexibility. All right.
06:51 Well, I'll cover something simple, async caching.
06:54 >> Simple.
06:56 >> It is simple in a sense.
06:59 >> Okay.
06:59 >> We have some nice stuff built into Python, like async, sorry, with like funk tools and the LRU cache and whatnot.
07:08 But from what I understand, those are synchronous only.
07:13 Basically, their decorators, those decorators wrap functions and the decorators themselves are synchronous.
07:20 So it only makes sense for them to wrap sync functions.
07:23 >> Okay.
07:24 >> So if you have an async function, but you want to do the LRU cache where you just put the decorator LRU cache, and then if it gets called with the same arguments, again, it doesn't even call the function, it just goes, "You know what? You've already called it with that.
07:36 Here's the answer." So, like if you're in a tight loop and you're pulling in some values and you've got to compute something with it through a function, but there's a good chance of repeat of those values, you can put an LRU cache in.
07:47 As long as that's pretty deterministic and you call it again, you expect the same output, you can make it fly by just adding one of those caches on it, right?
07:54 So, short version of this is, this is the same idea, but for async functions.
08:00 So I can have some function I want to call, and I just say @lrucache, and this way you give it a maximum size of results that it's willing, you know, inputs and matched up results it's willing to cache up.
08:12 And then if you call it with the same arguments, it'll give the same response back.
08:17 So that's pretty cool.
08:18 That's the last used version.
08:21 And then you also have time to live, a time to live, an async TTL.
08:25 So you can say any results, I don't care how many I've used, but just within the last 60 seconds.
08:32 And one thing that's really, really nice about that is it will expire results.
08:36 So maybe you're calling an API and you want to do rate limiting, but you only want to call it maybe once a minute.
08:43 That'll both make your code faster, but also not overrun your rate limiting that you might have with your API key and so on.
08:50 So here's a real simple way to add rate limiting.
08:52 It's just a time to live.
08:54 I guess you got to have the same input arguments, but assuming that you have the same arguments, That's one way to do it.
08:59 You can also specify the max size, which is pretty cool.
09:02 >> Yeah, or if you're grabbing something off of a service, like what's the temperature out?
09:08 I don't really care if it fluctuates every second, but every minute I might check it.
09:13 >> Yeah, precisely.
09:15 >> I don't, there's not a TTL.
09:17 >> All those kind of things.
09:18 >> So there's not a TTL on the normal LRU caches there?
09:22 >> I don't believe so.
09:23 >> Yeah. So that's actually cool.
09:26 I like the time to live part.
09:27 I do too. I like that. That really resonates with me.
09:30 The other thing that's pretty cool here is you can pass ORM objects, you can pass request objects, you can pass custom classes.
09:39 Even if the classes are not hashable, it will still go through and actually.
09:43 So one of the problems you can run into is if you, say if you've got a customer object or a product object or something, you call it once, you've created this object, maybe you got it from the database and you say, call the function with the LRU hash and it says, well, what object is this?
09:58 Have I seen it before?
10:00 And maybe yes or no.
10:01 And then you call it again.
10:03 It might have the same effective value, but it's not actually the same object.
10:07 But you might get it from the database again, so it has a different pointer, a different ID and so on.
10:11 That, I'm not sure what the behavior there is, but this one will actually look and see, oh, is it actually a class?
10:19 Well, then let's just get the dictionary and use the dictionary, the underlying field dictionary of the class to use as the match to see if I'm calling it again.
10:29 So there's some really cool functionality here.
10:32 Simple little class, but if you want to quickly add some performance boost async functions, you can add this.
10:38 >> Nice. Okay. This is neat.
10:40 >> Yeah.
10:41 >> Yeah.
10:41 >> That's fine.
10:42 >> Yeah, thanks. Also, it's entirely possible.
10:46 I don't think it does, but it's entirely possible to add async and synchronous support to a single decorator if you need to.
10:55 For example, I have the, what was it called?
10:59 The chameleon templates, FastAPI one that I created.
11:04 Let's see, look at that.
11:06 Number one result.
11:07 What a search thing.
11:08 So there's this FastAPI chameleon framework or library that I created that allows you to just do a decorator and say dot template and put a HTML template in the chameleon language on a FastAPI response.
11:23 And it returns a dictionary and that just turns it into an HTML response.
11:26 - Okay.
11:27 - This one in FastAPI, you can both have synchronous and asynchronous functions.
11:31 So this thing has to look and see if the inbound thing is a coroutine, an async coroutine, and it will dynamically generate the right wrapper, an async one or a synchronous one based on.
11:41 So it's not super hard.
11:42 It's also not super easy, but I did it, so it can be done.
11:46 Cool, anyway, that's a little bit of a diversion.
11:48 But this async cache versus a non-async cache, I feel like it could be one thing if it really, really wanted to be.
11:55 But I feel like the person who created it probably is just like, "I need this for async methods. Let's go." >> Yeah. It's almost too bad that the normal URL or your cache doesn't just do that.
12:05 >> Yeah. Maybe it's been updated too and I don't know.
12:08 But I don't believe it does.
12:09 >> I don't think so. Not currently.
12:11 >> Yeah. Not that I know of.
12:12 People can write us if we're wrong and we'll let people know next time.
12:16 Be great to do it.
12:17 >> I am never wrong.
12:19 >> Okay. Sometimes.
12:20 >> Because like I said, it's because it's a decorator, like you could make it start working that way.
12:25 That's a good feature to add.
12:27 >> Cool.
12:27 >> Before we move on, Brian, let me tell you about AI in real life.
12:32 >> Wow.
12:33 >> Yeah. This week's sponsor, this episode of Python Bytes is brought to you by the IRL podcast, an original podcast from Mozilla.
12:43 Thank you IRL and Mozilla for supporting the show.
12:46 If you're like us, We care about the ideas behind technology and not just the tech itself.
12:51 Obviously, we do a podcast on these things all the time, so we love talking about it, thinking about it.
12:56 Everyone out there knows that tech has an enormous influence on society.
12:59 Many of these effects are hugely beneficial.
13:02 Just think about walking around with your cell phone, you have basically the entire sum of human knowledge just constantly with you.
13:10 Other influences can have negative effects.
13:13 I really appreciate that Mozilla is always looking out for and working to mitigate these types of negative influences tech has on all of us.
13:20 So if these ideas resonate with you, you should definitely check out their podcast, IRL, the IRL podcast.
13:26 It's hosted by Bridget Todd.
13:27 And in this season, IRL looks at AI in real life.
13:31 Who can AI help?
13:32 Who can it harm?
13:33 The show features fascinating conversations with people who are working to build more trustworthy AI.
13:39 So just some of the examples of episodes.
13:41 There's an episode about how our world is mapped, like Google Maps style map with AI.
13:46 And what's really interesting is the data that's missing from those maps tells as much of the story as the data that's there.
13:53 So also an episode about gig workers who depend on apps for their livelihood.
13:57 And it looks at how they're pushing back against algorithms that control how much they get paid, seeking new ways to gain power and autonomy over data and creating better working conditions.
14:07 And finally, for political junkies, there's an episode on the role that AI plays when it comes to the spread of disinformation around elections, a huge concern for democracies.
14:17 You hear a lot about the US democracies, but more broadly, absolutely, across the world.
14:21 And I just listened to the first episode, the tech that we won't build, which explores when developers and data scientists should consider saying no to projects that can be harmful or strongly against their beliefs, even though, sure, you could technically build them, just 'cause you can and should, should you?
14:38 Anyway, if this sounds like an interesting show, try an episode for yourself.
14:41 Just search for IRL in your podcast player or visit pythonbytes.fm/irl.
14:46 Links in your podcast player show notes.
14:47 And thank you to IRL and Mozilla for supporting our show.
14:51 Thank you, Evan Strong.
14:52 - Yes, thanks.
14:54 So I wanna talk about organizing your code, Tim, actually.
14:58 Organizing your Python code kind of structure, structuring projects and everything, but there's more than that.
15:05 So I ran across this article called Organize Python Code Like a Pro.
15:09 And yes, it's got a lot of great advice and it's opinionated by one person, of course, but I think it's for the most part, really good stuff.
15:18 And also a couple of things that I don't normally see in these kinds of articles, and there's not too much weird stuff.
15:25 So sometimes it's a little too opinionated, but this is obviously where you can see where some of the opinions are held.
15:34 So take a look at, it talks about structuring your project.
15:38 For instance, one of the first things is use a source directory, SRC.
15:42 And so I try to do this, and I used to do it because there was an article about having your tests be seen.
15:52 So basically, if I'm doing a pack installable package, I'd like to have my tests see the installed package, not the local files.
16:00 And that happens sometimes if you're running, like say, pytest or unit test from the top level directory, and it might see the top level module and you don't want it to.
16:11 So source is a way to hide that.
16:13 But there's ways to get around that in testing.
16:15 So I don't really, it's not really a solid argument as it used to be.
16:20 This argument really is just, it looks nice in your code editor that you, Like here's an example of a non-source project where you have a couple of modules within the project and but alphabetically, they fall below, they're around your, you've got your test directory and your pyproject.toml and your source code's on both top and bottom of that, that's confusing.
16:45 So I actually kind of love this simple argument of just combine all the source in one place, it's nice.
16:52 So--
16:52 - I do like that too.
16:54 - I know the first reaction to this though is you're going to put a package level directory anyway, and having a package level directory in there if you have a package, instead of this source or something, that works too.
17:08 But anyway, this is interesting.
17:10 The one thing that gets me and it shows up here is this author is considering what I, so we have a problem in Python of what a package is.
17:20 A package is something I install from PyPI, but it's also within this Python documentation, Sometimes it's just a directory with an init file in it.
17:29 I don't know how you, so Michael, you teach people about that.
17:33 Do you ever stumble with this part or just?
17:36 >> Both seems complicated and overly simplistic.
17:39 For me, I think one of the challenges really I often run into is, how do I organize my files if I want a sub-module, if I want simple import statements?
17:52 >> Okay.
17:52 >> If you don't have, yeah, go ahead.
17:54 Do you think of directories with stuff, directories within a net as a module or as a package?
18:01 >> I do, but often I try to dodge that bullet and just not.
18:06 >> Not talk about it.
18:07 >> Not really get. Yeah, well, honestly, not talk about it.
18:10 If you're building a library, this matters very, very much.
18:13 If you're building an application, a web app, or a CLI app or something, often it doesn't matter because you're just running the top level, some top level like main or app.py or something, and it'll just pick it up whether it's a module or a package or just a directory.
18:29 >> I guess regardless of what we call directories, whether we call them modules or packages, this article calls them modules.
18:37 Then it goes on to talk about some other cool stuff.
18:40 Let's go down, naming things.
18:43 It talks about that there's really no files, there's modules.
18:47 There's no directories, they're all modules, but that's okay.
18:51 So this is some of the opinion stuff that you can, it's interesting, you can skip over it.
18:55 But the thing that I thought was interesting is these module names, they should be, they could be plural names.
19:03 And I never thought about that, and it kind of makes sense, like if you have, it gives an example, like drivers.
19:12 Drivers would be a module. Yeah, it'd probably be, the S on there makes sense.
19:17 >> It said keep config and main as single, but most things have an S on the end.
19:24 I never really thought about that before, but it does make sense of like from crawler storages, import get storage or something.
19:31 >> Yeah.
19:33 >> It's just a nice little extra thing.
19:35 Then it talks about naming functions and stuff.
19:40 This is something people get wrong all the time, so it's good to talk about it.
19:44 Name your functions with verbs.
19:46 it makes your code a lot clearer if your functions are methods or verbs.
19:50 Unless you have to jump through giant hoops to make it work.
19:53 But if you have to jump through giant hoops to make a verb work, maybe it's not really one function, maybe it should be two or three, but we'll see.
19:59 >> Yeah, or a property instead of a function.
20:02 >> Yeah, or a property, right.
20:04 Then class names, one of the things I never thought about also was class names should be singular, So classes should be singular unless it's really a container.
20:16 So don't name a class orders because it's going to describe multiple orders.
20:22 It's an order, it's an order class, not an orders class.
20:25 So that's a good thing.
20:28 One of the things I loved about this article also is there's two things that we talk about, we use a lot, but I don't think very many people talk about it too much.
20:38 Well, it's the dunder and net thing.
20:39 I'm going to pop down that not the the dunder name equals dunder main.
20:43 That's used all the time.
20:45 and so it's good to talk about that of if you want to execute a module itself, use that.
20:50 But the if you one of the things I tried to do recently that I kind of didn't know how to do right off the bat is a directory within a net.
20:58 If it also has a dunder main, then you can use the dash M thing on it.
21:03 so if you include like dunder main, then you can use Python -m module name when you're running.
21:12 >> Interesting. Okay.
21:13 >> Because I had a library I was working with and I was like, I'm using -m for everything else.
21:20 I'd like to have the entry point for my application be usable if I do -m also.
21:26 How do I do that? This is how you do it.
21:29 It's neat to have this in right away because I don't know if it's really a beginner thing, but it's still cool.
21:35 Yeah, I like it a lot. It's like entry points, but simpler.
21:38 Yeah. Anyway, so decent article. There's some opinions there, but that's okay.
21:44 We like opinions.
21:45 Absolutely. We do, we do. All right. Well, do you know what else we like, Brian? Follow-up.
21:50 Yay! I was going to do this. I'm glad you're doing it.
21:53 Too late. I grabbed it. I grabbed it because this one is a good one. So, remember last week you spoke about CLI apps and doing OAuth, and you've got to remember the tokens the example you gave was from Twitter, but it could be from all over the place.
22:06 So Trent, we got multiple pieces of feedback.
22:10 One about encrypting the stuff that goes into your user profile.
22:14 I can't remember who, I apologize about forgetting the name, but someone sent in a message that says, well, the AWS CLI just puts your token straight there unencrypted.
22:22 So there's that. I said maybe you should encrypt them somehow, and I agree with that still.
22:29 But Trent sent in this project called Keyring, And key ring is key ring or vault, vaults, those types of things.
22:36 There are ways, sort of more managed central stores of this type of information, right?
22:42 On macOS you hear, and it put it in your OS X key chain, right?
22:48 You probably have heard that or the Windows Credential Store or those things that the actual operating system is protecting from other apps to go look at it.
22:55 But it's basically just encrypted, login, password or tokens, yeah?
23:00 So this keyring thing that gested is something like that, but it works to Python library, it works across platform, and it works with different backends based on both what platform you're on and other things you might decide.
23:15 So it's a library that gives you access to system keyring services from Python, which I think is fantastic.
23:22 So on macOS, that's Keychain.
23:25 On Linux, it's the Secret Service or the KDE 4 and 5K wallets.
23:32 And then on Windows, it's the Windows Credential Locker.
23:35 - Okay.
23:36 - Right, and so in there, you can just call set password and get password and off it goes.
23:42 And that's pretty much it, right?
23:44 But it's stored in a nice encrypted, not just encrypted, but protected access way for the OS.
23:50 - Yeah, so I actually forgot about this.
23:52 I actually use this for testing all the time, but I never thought, I didn't think about using it for a command line application.
23:59 Interesting.
24:00 Okay, how do you use it for testing?
24:03 So we have, some of the issues are we have different devices that we're testing against that are password protected devices.
24:12 And so you had in order to access them, you need a login and password to run commands against them.
24:20 And so to be able to do that, we need the, if you're SSHing into something or something like that, that's part of your process, you have to have those credentials somewhere, and we don't want them in our source code.
24:34 That's the gist of it is we don't want them just to be, yeah, we don't want them in the source code and checked in to GitLab to have the whole company be able to read them.
24:45 It's still protected, it's an internal thing, but maybe you're on GitLab or GitHub or something, and it's a public repo.
24:53 You don't want any passwords right there, but you can have them stored on your local machine and then pull them out with keyring.
24:59 >> Right.
24:59 >> It surprised me a little bit that they're just the Git passwords are a thing.
25:03 I expected it to be like a Git the password hash or something.
25:08 But I have to remember this isn't verifying passwords, it's having them to be able to send them to another system.
25:16 >> Ideally, that one is storing the hash, not the real thing.
25:19 >> Yeah, exactly.
25:20 >> Yeah.
25:21 >> I don't know if it works.
25:23 >> I don't know if this would be, this is still cool and I'm glad we're covering it, but my original question was around, is this what's a reasonable thing to store passwords for sessions for command line application?
25:36 I don't know if keyring would work, but I haven't tried it yet.
25:39 Maybe if you have a set password, maybe it will work, maybe it stores something locally.
25:43 So I'll have to try it out.
25:44 >> Yeah, I think that it will.
25:46 >> Okay.
25:46 >> The question that I was wondering is, what about the get password?
25:49 Is that restricted to the process that put it in there?
25:53 >> Yeah.
25:54 >> Or is it anything running on the system?
25:55 >> Yeah, exactly.
25:57 Can you just start arbitrarily asking for stuff?
25:59 Probably some restrictions there, but I don't know exactly what they are.
26:02 Penfill out in the audience says, I'm not mistaken, Poetry is using the FITs installed.
26:09 So that's where your PyPI credentials get installed.
26:12 You can check out issue 210 from Poetry.
26:15 And down here somewhere says, they talk about ways in which you could store.
26:21 And it says, why not just make key ring a dependency?
26:24 - Okay.
26:25 - Yeah, if this approach, why not simply make key ring a dependency and so on.
26:28 And so yeah, it talks about basically using this to store your PyPI credentials.
26:34 And that's a CLI app.
26:35 - Perfect then, we have an example.
26:36 - It sounds like a pretty good match.
26:38 Yeah, nice little example.
26:39 Yeah, you can just follow along what they're doing there.
26:41 So thank you Penfil for pointing that out.
26:43 - Yeah.
26:43 Well, anyway, I don't currently have any use for this.
26:46 I think it might be useful even outside of, I have this interactive application, for example, storing secrets.
26:54 You know, if you want to have the database connection string to your app, right?
26:57 This might be a good way to do it.
26:59 And one other thing that's interesting is you can have third-party backends.
27:02 So you could have just encrypted text files, you could have the Dbus API for Linux, Google Sheets, I don't know about this, but.
27:12 (both laughing)
27:13 - It does say for use with IPython secret, so maybe it encrypts them.
27:17 But more realistically, we've talked about Bitwarden before, an open source password manager, which is really nice.
27:24 I use that for a few things.
27:26 - Okay. - And so that has a CLI aspect.
27:28 You can have Bitwarden as a backend.
27:30 You can write your own as well.
27:32 And 1Password has a CLI option as well for storing SSH keys even.
27:37 So you could even put your SSH keys in there and whatnot.
27:40 I don't know if this would pull it back correctly, but there's a lot of ways to store things and say one password and then access it with a CLI.
27:47 Maybe you could plug this in.
27:48 So just it's another provider, which is cool.
27:50 - Yeah.
27:51 - Yeah, anyway, seems really nice to me.
27:53 If I have a use for it, I'll definitely look into it more.
27:56 - Yeah, cool, nice.
27:57 - Yep, all right.
27:58 Hey, that might be all of our topics for the day, huh?
28:00 - I think so, yeah.
28:01 - So, extras, you got any extras?
28:03 - I just wanted to say that I am working on a couple things.
28:09 I'm editing my pytest course, of course, still working on that.
28:14 But the other thing that I just started, which I'm super excited about, is I just started taking a FastAPI course.
28:20 - Oh yeah?
28:21 - It's really neat.
28:21 The instructor's awesome, yeah.
28:23 (laughing)
28:24 - Awesome, yeah, thank you.
28:26 That's the FastAPI course, this live course that I'm doing this week and next week, right?
28:30 - Yeah, yeah, so I'm taking it from Michael, and if anybody is, if you've never taken one of the online courses with Michael or a live course, it's just really excellent.
28:40 He's a good instructor, so it's good.
28:42 - Thank you very much.
28:43 Yeah, I love it.
28:44 We're having a good time just playing with code as a group.
28:46 - Yeah, how about you?
28:47 - I have, I think I have some extras just really quickly here.
28:51 Brian Skin, who's been a co-host before, sent us a tweet and said, "Attention Python Bytes." And that went over to this message from Jeff, Jeff Huntley.
29:02 And it says, "GitLab, are you all right?" And this is linking to an article from the register.
29:09 It says, "GitLab plans to delete "dormant projects in free accounts, "hoping to save a quarter of the hosting costs "by binning repos that haven't been touched for a year." - Yikes.
29:18 - That's a little nerve wracking because just 'cause it hasn't been changed doesn't mean it's not useful.
29:23 - Yeah. - Yes.
29:24 - Oh, maybe I keep my recipes up there and I haven't added any recipes lately.
29:28 - Yeah, maybe nothing's changed or whatever.
29:30 So a couple of things.
29:33 PSA if you have a GitLab project, maybe just add a period to some text file or something and check that in.
29:42 >> Spam your own repo with trivial PRs.
29:46 >> Yeah, exactly.
29:47 I fixed this misspelling here by changing the word and the more.
29:52 Mario Munoz says, they may be reverting this.
29:55 Okay, so this was just from four or five days ago.
29:58 And Pamphill says, yes, they did.
30:00 "Okay, well, it sounds like they had the same face.
30:03 Many people had the same reaction that we are going, "Oh boy, this seems like a bad idea.
30:09 I'm glad this was changed." Yeah, Pamphle says, "Because of the huge backlash." I can imagine.
30:14 - Yeah.
30:15 - All right, well, I guess I'll have to continue to pay their million dollars extra per year to host things that people put up on there where they said they would host it.
30:22 - Yeah, well, hopefully they, okay.
30:24 Even if you did that, hopefully they would email people at least.
30:27 Hopefully your current emails.
30:28 - Yeah, exactly.
30:29 How to like Google Voice.
30:30 Please log in within the next 30 days to keep your phone number, or whatever it is they always did to me.
30:37 Okay, well with that, I think it brings us to some jokes.
30:40 You got some jokes to tell, and I brought a quick one as well.
30:43 - Okay. - You wanna go first?
30:44 - Sure, I'm not gonna read the ones up here, but I got them, I got a couple jokes from a place called, from a GitHub repo that's dad-style programming jokes, which is perfect for me.
30:55 So I got a couple.
30:58 How do programming pirates pass method parameters?
31:01 - I don't know.
31:02 - With virargs.
31:03 (laughing)
31:05 - Awesome.
31:06 - Okay, second one.
31:07 How do you get code?
31:09 How do you get the code of your bank vault?
31:12 So you can break into the bank.
31:13 - I don't know.
31:14 - You check out their branch.
31:15 This is bad.
31:17 - Nice, I love it.
31:18 - And then one of the things I liked on the top of this, it says, "Unfortunately, these jokes only work "if you get them." Ah, bad.
31:25 - Oh, so good.
31:27 And it's a GitHub repo, so that's actually fitting.
31:29 So anyway.
31:30 - It's very self-referential, very meta.
31:32 - Okay, how about you?
31:34 - Here's a quick one before I put it up on screen.
31:36 You know how there's this constant not built here syndrome?
31:40 Like sure, this key ring is cool, but did we build it?
31:43 No, I bet we could build a better key ring than that.
31:45 And like, we'll get a team together to build key ring.
31:48 Right?
31:48 So here's a picture of normal people acting like developers.
31:53 So there's these two construction workers with their hard hats on, there's a screwdriver with a $2 tag on it because it was just purchased.
32:00 And one guy's outraged.
32:01 What?
32:02 Did you buy a screwdriver instead of building your own from scratch?
32:06 - Exactly.
32:07 Yeah.
32:08 - Yeah, pretty good.
32:09 - What?
32:10 You're using Hugo?
32:11 Why didn't you build your own blog engine?
32:13 - Exactly.
32:14 First, I'm gonna build my own Markdown parser so I can have better tables.
32:18 Let's go.
32:19 - Exactly.
32:20 Yeah.
32:20 - Yes, indeed.
32:21 - So.
32:22 - All right, well, excellent podcast as always.
32:23 Thanks for being here.
32:24 - Thank you.
32:25 - You bet, and thank you everyone for listening, watching, however you've been part of this.
32:30 - Yeah, thanks a lot.