Learn Python with Talk Python's 270 hours of courses

#160: Lektor: Beautiful websites out of flat files Transcript

Recorded on Wednesday, Apr 18, 2018.

00:00 What is the fastest, most scalable web platform out there?

00:02 Is it Pyramid running on top of MongoDB with the Redis cache?

00:06 Maybe Flask and Postgres as a service with some high-performance cluster?

00:09 Or some funky Go API framework?

00:12 No, it's static files.

00:14 But today, static files does not mean that you write a bunch of HTML.

00:18 With static site frameworks and generators like Lecter and Pelican, you can use data to drive the creation of static sites

00:24 and then host them wherever makes the most sense for you.

00:27 On this episode, you'll meet Joseph Nix, who works on Lecter, a Python-based static site generator.

00:32 This is Talk Python to Me, episode 160, recorded April 19, 2018.

00:37 Welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the ecosystem, and the personalities.

00:57 This is your host, Michael Kennedy.

00:59 Follow me on Twitter, where I'm @mkennedy.

01:01 Keep up with the show and listen to past episodes at talkpython.fm, and follow the show on Twitter via at Talk Python.

01:08 This episode is sponsored by Linode and Rollbar.

01:11 Please check out what they're offering during their segments.

01:13 It really helps support the show.

01:15 Hey, Joseph. Welcome to Talk Python.

01:17 Hi, thanks for having me.

01:18 Yeah, it's great to have you here.

01:19 I'm really excited to talk about Lecter and, more broadly, these static site generators because they're such an interesting way

01:27 to build web applications that I think are really quite the opposite of full-stack, data-driven, scale-out, this and that, right?

01:37 Yeah, definitely.

01:38 But they definitely have a huge place, a good need, I think.

01:42 Yeah, and I think Lecter lives in a pretty interesting space in that realm as well.

01:48 Before we get into it, though, let's start with your story.

01:52 How did you get into programming in Python?

01:53 My story is kind of fun, I think.

01:57 So I didn't start out wanting to be a programmer at all.

02:00 I grew up interested in physics and math.

02:03 That was all that I was about.

02:05 I wanted to be an astrophysicist since I was a little, little kid.

02:09 So I went to school at UAH in Rocket City, Alabama.

02:13 That's where they built the Saturn V.

02:15 And I wasn't taking any programming classes except for one that was mandatory.

02:21 It was a C++ class that I struggled through.

02:24 But I met some cool friends.

02:30 And for fun, we would spitball ideas.

02:33 We'd talk about cosmology and things like this.

02:36 And we ended up, again for fun, inventing a kind of rocket engine.

02:41 So I didn't see that coming.

02:45 It's a small thing, at least physically.

02:51 It's a kind of electric propulsion device, which I could talk about forever, basically.

02:59 But it's pretty cool.

03:00 And we researched it on paper.

03:02 And we decided to form a company to protect the intellectual property with aspirations of actually doing physical R&D and doing something with it.

03:12 Right.

03:13 So we did that.

03:15 And then we realized, well, okay, now we've got this company.

03:18 And we want to do rocket research.

03:19 And we have no money at all because we're poor college students.

03:23 Right.

03:24 There's no hiring engineers or things like that, right?

03:26 No.

03:27 We considered various ways to remedy that.

03:32 But what we decided was we looked at everybody else that was doing something similar.

03:37 There's all sorts of space entrepreneurism going around at the time and still now.

03:43 And almost all of these that we could find were founded or funded by people who made their money in software.

03:51 Right.

03:51 I mean, we've got SpaceX.

03:52 We've got the Blue Origin.

03:55 Yeah, Blue Origin.

03:55 Yeah, yeah, yeah.

03:56 Exactly.

03:57 And some probably other, a bunch of others we, I don't know about.

03:59 Virgin Galactic.

04:00 Yeah, yeah, exactly.

04:01 Richard Branson.

04:01 I mean, it's not entirely software, but a lot of it.

04:04 But absolutely.

04:05 People, all these software executives and founders, it seems like they maybe even had it in their mind a long time ago that this is what they wanted to do.

04:15 They really just wanted to go to space.

04:18 And they thought of some novel software applications that are useful in and of themselves and interesting in and of themselves, but will help them get to space as well.

04:28 That's really interesting.

04:29 So how did that get you into programming?

04:30 So we decided we needed to teach ourselves software so we can make some money to do this rocket research.

04:36 So that's exactly what we did.

04:38 So kind of from the very beginning for me, I was talking with my friends and we decided what we wanted to do.

04:46 We looked at the various programming languages out there from a completely fresh perspective because none of us were programmers really.

04:52 We looked at PHP, we looked at Fortran, we looked at C, Python, and we kind of felt that Python was maybe the way to go.

05:00 It seemed like it was becoming popular.

05:02 We read about why.

05:04 We experimented with a few languages and we liked Python.

05:08 So we dove in and it stuck.

05:11 It was very easy to pick up.

05:13 That's definitely one of its superpowers.

05:15 And also so many of the languages that are easy to pick up there that way because they give up sort of the professional high-end proper architecture.

05:25 And Python seems to live in this space where like you can start without all the structure and objects and separation and packages.

05:33 But it can grow into that as you need it, right?

05:35 So I think that's part of the secret sauce.

05:37 Yeah, definitely.

05:38 When we first started out learning Python, I was still having a hard time wrapping my head around OO.

05:43 You know, just doing very basic imperative and functional things to get our feet wet.

05:49 But it grew.

05:51 And I've been doing Python now for a decade and I feel pretty comfortable.

05:56 We'll get into the lecture and all this stuff.

05:57 I just want to ask you, given that story, did you watch Falcon Heavy launch?

06:01 Yes, I did.

06:02 Oh, my goodness.

06:03 It made me cry.

06:04 I thought that would be kind of a major thing.

06:07 But then like you watch it and it's just like, oh, my gosh, like people are still doing amazing stuff in space, even though the government seems to have given up on it.

06:15 Yes.

06:15 And that was really frustrating, too, at the time.

06:18 So we started learning Python back in like the mid 2000s, which was right before the economic crash in 2008.

06:26 And people, which is when we were starting to get good at Python, we were trying to be consultants, but it's hard to find a job.

06:34 People weren't really hiring then.

06:35 And all these spaceflight companies were struggling, too, because, again, everything was kind of suppressed a little bit.

06:43 And they were trying to get off the ground running with something aggressive in the first place.

06:48 But they've pushed through and they've done great things.

06:52 And I'm super excited to see where all where all of them go.

06:55 Yeah.

06:55 Watching those two outer rockets land and I guess the third one try to land was just it was like, oh, my gosh, we are in science fiction land.

07:04 But it is like happening.

07:06 Right.

07:07 It's just when I saw that, I'm like, that is something you would see in a movie.

07:10 That is not something you would see in reality.

07:13 No, it was just unbelievable.

07:15 I think they had a video where they tried to show what this will look like before it actually happened.

07:22 And they had the two rockets land separated in time.

07:25 And I don't know if they were planning on them actually landing just identically together.

07:31 My guess is they wanted that, but they weren't going to bank on it.

07:34 So they didn't want to get everybody's hopes up.

07:35 Boy, it just looked ridiculous.

07:37 Yeah.

07:38 Yeah.

07:38 Yeah.

07:38 I'm so looking forward to the next five years.

07:40 What's happening around there.

07:41 All right.

07:42 We could we could totally turn this into a space show.

07:45 But let's stay focused on the stuff that came after your project.

07:49 Right.

07:49 Just to sort of close it out.

07:51 Like, are you is that company still exists?

07:53 Has anything happened of it?

07:54 Yes, definitely.

07:55 We have grown in skill and we're now a stable company.

08:01 Our company is named Terminal Labs.

08:03 We're a small Python consulting shop.

08:05 We work contracting for other companies to do whatever it is they need.

08:10 In the past, we've done a lot of full stack web development.

08:13 We've worked with Django and Flask, some really big Django projects.

08:17 And we've also loved it.

08:20 Any chance we can get to do any science.

08:23 So data science and machine learning are really exciting.

08:28 And we're getting more and more into that all the time.

08:30 We've got a pretty strong DevOps background.

08:32 So all this is keeping us employed and raising our skill level further so that we can eventually

08:39 make a rocket.

08:40 Awesome.

08:41 All right.

08:42 So that sort of brings us to what you're doing today.

08:44 And that's really where you're still focused is sort of continuing to grow the

08:48 consultancy and stay and play and basically play in the science space when possible.

08:54 Yes, absolutely.

08:55 And making connections.

08:57 And yeah, our goal is to get to space and how exactly we're going to transition there.

09:04 Time will tell.

09:05 We've got some ideas.

09:07 But this has been a pretty good course so far.

09:10 And I think it'll work.

09:11 Very cool.

09:11 Glad to see that that's still going.

09:12 So let's talk about the project that you've been involved with sort of most broadly at first

09:18 with static site generators.

09:21 So many people who listen to the podcast are web developers, but a lot of people are scientists

09:26 or data scientists or even students.

09:29 So maybe just like could you compare and contrast a static site generator experience to like, let's

09:37 say, like a traditional web app.

09:39 You talked about Flask and Django, either of those.

09:41 Yeah, absolutely.

09:42 So with a traditional web app, you have a server.

09:46 There is a server on the cloud that you that a user will hit and make a query to.

09:52 And then that server does some logic and often connects with a database to dynamically generate

09:59 something to return to your browser.

10:01 And a static site generator doesn't need any of that.

10:05 And often I'd recommend against it.

10:08 Like you could put it behind Flask, but there's really no need.

10:11 The build products of a static site generator are basic HTML.

10:15 The tradeoff, like, you know, it seems at first like so the tradeoff is I could just create a bunch of

10:22 JS, CSS and HTML files and just write them.

10:26 But that becomes super tedious super quickly, right?

10:29 Like if even if you just want the same look and feel across multiple pages, right?

10:35 Like if you've got 20 pages like that and somebody comes in, either boss, client, whatever it says,

10:41 I would love for that background over here to be blue and the font to like reorder the menu.

10:46 That's not hard, right?

10:47 But if you actually hand code it, like it sucks, right?

10:50 You've got to go and change all those.

10:52 But on the other hand, if you've got to maintain databases, scalability, security patches, etc.,

10:57 that also can be painful.

10:59 Sometimes it's totally needed.

11:01 Like for my site, like it has to be dynamic.

11:03 It absolutely needs a server and a database.

11:06 But many sites don't, right?

11:08 Absolutely.

11:09 The history of it is, is we started with those raw HTML and CSS.

11:12 And that was absolutely a pain.

11:14 You're completely right.

11:15 I hate coding CSS.

11:18 But the reaction to that was to build these very complicated web servers.

11:22 And not everybody needs that either.

11:25 So these static site generators came around as a bit of a compromise for people who don't want to build these basic HTML sites with CSS by hand

11:36 because that is enormous pain.

11:37 But they don't need the power of an actual logic backend in a database.

11:43 All they really want is to make their lives easier creating the static content.

11:48 And things like Jinja really help a lot with that and web templating.

11:54 Right.

11:55 And so, for example, like you probably still want some kind of data-driven site created.

12:01 Like you could have a blog and you want to add a new entry and have that appear and be linked to possibly under various categories and stuff.

12:08 But you want to be able to – like I guess the thing is you don't need to show a different version of the blog to anyone, right?

12:15 It's totally fine if they all get the same one.

12:18 So instead of doing that at runtime on the server over and over but always giving the same result, like just crank out – like somehow on your machine at a like a move to production time, you generate that.

12:29 And then you just put the static files there, right?

12:31 And it ends up being really nice in production too because all these files are pre-built.

12:37 So all that you need to do is put the HTML on a CDN or something and then they get served incredibly quickly.

12:44 So it's very performant.

12:45 So from a production standpoint, it's faster to do this for the user than to actually query, for example, a Flask backend that is just doing the same thing.

12:56 Just generating a simple HTML for everybody and giving it out.

13:00 I guess you can even mix them, right?

13:03 So suppose you've got some section of your app that is like a store.

13:07 Obviously, you would like people to – that to be dynamic.

13:11 But the rest of it, maybe not.

13:12 You could use something like Nginx and like URL routing to say this part routes to like a Flask app or Pyramid app.

13:18 This part routes to the static content.

13:21 You can definitely do that.

13:22 Nginx is a great way to segregate those sorts of things.

13:25 So you can have a static site generator made with Lecter, for instance, and a Flask part of your website that is dynamic content, but not the blog because the blog doesn't need that.

13:37 Not the flat landing pages because it doesn't need that.

13:40 And you could even go and use JavaScript on a static page to query dynamic content if you wanted.

13:48 Right.

13:48 If you wanted to go down the sort of rich front-end web framework type thing like Angular, React, or whatever, that could be all fully static.

13:56 But then like maybe there's a Flask API, for example.

13:59 Exactly.

13:59 So you could even shimmy in some dynamic content into a static site.

14:03 And how easy that is depends on, of course, how comfortable you are with all those technologies and the complexity of your dynamic content.

14:12 So the more complicated that gets or the more comfortable you are with Python instead of JavaScript, maybe the more inclined you should be to use Flask or Django.

14:22 Yeah, that makes sense.

14:23 So maybe give us some examples.

14:25 We talked about Lecter.

14:27 Let's take one step back.

14:29 One thing that I think we did, obviously we touched on the deployment and simplicity.

14:33 One thing we haven't touched on is just the performance of static sites.

14:38 Obviously, you talked about the CDN and that's good, but the consequences of high-performing sites are really important.

14:46 Right?

14:47 I think Amazon did a study saying for every 500 milliseconds of latency they add, they lose 1% of sales or something like that.

14:56 It's a big deal.

14:59 Yeah, and I'm sure it's not linear.

15:01 You add that fifth bit and it's like eventually people are going to go away and it's going to become nonlinear.

15:07 But that's important, right?

15:09 Yeah, that margin is very important for most businesses.

15:12 And even if you're just trying to make your own personal blog become more popular, it matters to you if your user base grows by 1% or 10%.

15:21 It matters.

15:22 And it also, I think it feels different when you're on a site that you're like, dang, that is basically instant.

15:28 Like that feels almost instant to me as I work with it.

15:32 Whereas the other one, like if anyone has worked with SharePoint, they know what the opposite of that feels like.

15:38 Right?

15:38 It's just like slow, painful.

15:41 Right?

15:42 I'm waiting again.

15:43 Like it just, even if it doesn't make people go away, it engenders a different experience with your consumers or your people.

15:51 Absolutely.

15:51 It's got an effect on your mood.

15:54 Even if it's subconscious, even if it's slight, it makes you a little less happy, a little more agitated if it's slow.

16:00 This company doesn't really delight me, right?

16:02 Right.

16:03 Things like that.

16:04 So, and I think Google, you can never be sure what Google cues off of because they would be massively game as soon as they let that out of the bag.

16:13 But I think site performance also affects ranking.

16:18 Yes, I believe it does.

16:20 And they've got, Google's got their own tools even to check site speed.

16:24 And if you use a static site generator to produce static sites, you're generally going to score pretty well about that.

16:31 Exactly.

16:32 Yeah.

16:33 You can do little things to make your static content even faster and optimize above the fold content and things like this.

16:41 Like minification or bundling and things like that?

16:44 You can minify.

16:45 You can compress.

16:46 You can make sure that all the CSS that's relevant to content that you see above the fold, that is when you first load a page and not below it when you scroll, you can make sure that CSS is loaded first.

16:59 So that there's an even smaller flash of unstyled content.

17:03 Yeah, that's a cool idea.

17:04 Yeah.

17:04 So you can do things like that.

17:06 But if you simply just have static content on a CDN, no matter what, you're going to try to make it really slow.

17:13 That's absolutely right.

17:14 That's pretty awesome.

17:15 And so all those benefits accrue to those.

17:18 And I think the static site, there's also sort of data driven, but then maybe mixing either like backend services over JavaScript or like a section of various sections that are fully dynamic.

17:29 I think that's a pretty interesting way to think about going beyond just, well, I have a couple of pages and a static site.

17:35 Definitely.

17:35 You can interplay them.

17:37 You can mix and match.

17:38 And that will increase the speed of all the static components, which will make your users happier.

17:44 Yeah, absolutely.

17:47 This portion of Talk Python to me is brought to you by Linode.

17:50 Are you looking for bulletproof hosting that's fast, simple, and incredibly affordable?

17:54 Look past that bookstore and check out Linode at talkpython.fm/Linode.

17:59 That's L-I-N-O-D-E.

18:01 Plans start at just $5 a month for a dedicated server with a gig of RAM.

18:05 They have 10 data centers across the globe.

18:08 So no matter where you are, there's a data center near you.

18:11 Whether you want to run your Python web app, host a private Git server, or file server,

18:16 you'll get native SSDs on all the machines, a newly upgraded 200 gigabit network, 24-7 friendly support,

18:23 even on holidays, and a seven-day money-back guarantee.

18:26 Do you need a little help with your infrastructure?

18:28 They even offer professional services to help you get started with architecture, migrations, and more.

18:34 Get a dedicated server for free for the next four months.

18:37 Just visit talkpython.fm/Linode.

18:40 So let's talk about some of the tooling that we might use for this.

18:46 So Lector, obviously, is pretty awesome.

18:48 Yes.

18:48 But it's not the only one in the Python space, right?

18:52 There's a couple of others.

18:53 Maybe you could just touch on those, just so people know kind of what, if they see built with something at the bottom, they're like,

18:59 oh, that was a static site generator.

19:00 Python or not, there's a handful of static site generators out there.

19:04 A couple popular ones, I think, are Pelican and Hugo.

19:07 Hugo is definitely very popular.

19:09 I think that's written in Go.

19:10 And they predated Lector, I believe.

19:14 And what they do is they use templating and Markdown.

19:19 So they try and make it pretty easy for you to make your content in Markdown.

19:23 And then they have a little backend functionality with template context.

19:29 So you can query things as you're building your static content so that you don't have to write the same HTML over and over and over again,

19:36 which is really handy.

19:38 Right, like an overall layout page with your navigation and footer and CSS and JavaScript,

19:42 et cetera, right?

19:43 Yeah, not having HTML templates is a thing of the past that people should not be doing anymore.

19:49 But I deployed them from front page.

19:53 Come on.

19:56 Right.

19:57 Right.

19:57 People do still do them.

19:59 That's absolutely true.

20:00 But I don't think they really should anymore.

20:02 So using these templating languages and the static site generators make people's lives easier

20:07 so they can not have to expend very much effort to expand their website.

20:13 And a lot of these static site generators have themes.

20:19 So you can build off of the theme too, which is really handy for a lot of people.

20:23 So they don't have to come up with their own CSS, at least from the back.

20:27 But Lecter came after these and it learned from some of their deficiencies too.

20:33 Because again, going back to the history, I think the static site generators came out after the more complicated web frameworks did.

20:41 And these servers.

20:43 So they were a step back from the initial reaction against pure HTML.

20:48 So pure HTML was horrible.

20:50 Then it went to web frameworks.

20:51 And then we got static site generators that kind of existed in between.

20:54 And Lecter has all the features of those static site generators.

21:01 But it's got some of the additional features that the web frameworks have that make life even simpler.

21:07 Okay, like what?

21:08 Like a CMS.

21:09 So far as I know, Lecter is the only static site generator that comes with a built-in CMS out of the box, ready to go.

21:16 Yeah, that is pretty interesting.

21:17 So I guess maybe let's do like a high-level flyer of just how it works.

21:21 So with Lecter, Lecter is a thing you install onto your machine.

21:27 And then it's a command line application you run to generate the static file site structure.

21:35 And then you can use it also to serve up that content in a way that will let you basically click a button, like a little edit button on any page, type away on it.

21:44 And it will under the covers actually write or save the markdown and then live reload that as you develop your site.

21:53 And then I guess there's probably like some kind of Lecter deploy step that like finally builds it out to the final HTML.

21:59 Yes, there is.

21:59 So it is a program that you download and install and you run it over the CLI.

22:06 But you don't have to interact with the CLI very much to use it.

22:10 I had it generating sites on all these two commands.

22:12 Right.

22:13 Lecter quick start and then Lecter server.

22:15 And then I like I was I was going to get it.

22:18 I was playing with it.

22:18 It's fun.

22:19 Good.

22:19 And that's how it should be.

22:21 So the previous static site generators would mean that you had to either open markdown and edit it in whatever editor you like or just do everything in the terminal.

22:33 And not everybody is comfortable with that.

22:35 We're trying to make static sites accessible to people who aren't necessarily programmers.

22:40 Well, and static sites are especially beneficial to people who are not capable of like all the CLI stuff and running databases.

22:48 And that like it's exactly the people who don't want to do that.

22:52 The flask pyramid SQLAlchemy type stuff for whom this really benefits because the deployment and like running at the site is crazy easy.

23:00 And so, yeah, having that sort of focused in that area is really nice.

23:04 Right.

23:04 So would you say like if you're working in a company and somebody comes to you and says, hey, can we build this new site?

23:10 I'm thinking about using SharePoint or something like that because we have to be able to keep track of X, Y or Z or whatever.

23:16 Do you think Lecter might be like, hey, let's not use that.

23:21 Let's set up a Lecter thing and you can actually use the CMS and manage it and stuff like that.

23:25 Would that be good?

23:26 It depends on a few things.

23:28 Like if someone needs complicated user management, they want to segregate employees and say certain employees have certain permissions and others don't.

23:38 Then Lecter is not a fit for that.

23:42 Doesn't make sense.

23:44 Yeah, because static files don't have great permission role things other than at the OS level.

23:50 Right.

23:51 And that's actually part of the beauty of it really is because there's no user permissions.

23:57 Everybody can do everything and it makes things simpler.

24:00 It takes away a big chunk of complexity out of the system.

24:03 Yeah.

24:04 That's the tradeoff, right?

24:05 It's that you get this super fast, super simple system, but it doesn't do everything, right?

24:09 You could make it do everything, but then it wouldn't be simple.

24:11 It would be hard again.

24:12 It would be SharePoint.

24:13 What I have seen people do is they will run Lecter on a work LAN and they'll have all the employees use the same Lecter setup so they can all edit pages as they will.

24:26 And if you trust your employees to not make horrible mistakes, then that works really well.

24:32 You don't necessarily need all of those permissions.

24:35 Yeah.

24:36 I feel like a lot of companies go too far and they're like, well, we've got to lock everything down and restrict people and whatnot.

24:41 And it just blows my mind.

24:43 If you don't trust these people, why are you employing them?

24:47 Like if literally you're like, I will not trust this person to touch this file, like that person should probably just not work here as of this afternoon because like that is a strong statement for so many things.

24:58 But I see it over and over in these companies, right?

25:00 I mean, I guess there's a difference between protecting yourself from like I clicked on a phishing link, but there's a lot of these cases where it's like clearly we don't trust our employees and like, well, why are you employing them?

25:11 Right.

25:11 Right.

25:12 And I get to concerns about people doing things by accident.

25:16 So not like maliciousness, but accidentally deleting your content.

25:21 But you can protect against that in other ways, too.

25:23 You don't necessarily need complicated user permissions.

25:25 Dropbox even has backups you can take.

25:28 That's right.

25:29 And you could even have someone who is maintaining the lecture deployment locally on a LAN and five content producers adding in content.

25:39 But the one person actually making git commits every now and then by hand because they know what they're doing.

25:44 Right.

25:45 You could even automate that.

25:46 Right.

25:46 Just every hour, just commit the site.

25:48 Whatever it is, it's like this time of day we commit it.

25:51 And that way, at least you have a way to go roll back.

25:54 There's a version history there.

25:55 Exactly.

25:56 Yeah.

25:56 Very cool.

25:57 Very cool.

25:58 So maybe let's do like a rundown through some of the core features because I think they're pretty awesome.

26:05 We've been sort of touching on some of them.

26:07 The first one is around deployment.

26:09 Right.

26:10 It says basically you can deploy anywhere.

26:12 So I could go and I could set up something kind of probably over the top like an EC2 Linux machine or Windows machine and copy my files up there and serve it there.

26:23 Maybe I could set up like a $5 Linode server, which would be pretty sweet.

26:28 But being static files, there's even like more options.

26:31 Right.

26:32 Like I could go way basic and put it on S3 or where else could I put it?

26:36 Yes.

26:36 Well, just like you're saying, because it's a static site, it can go anywhere.

26:41 It can go on any CDN at all.

26:44 Basically, you can put it on S3.

26:46 What we do for our own personal website is we host it on S3 and then have CloudFront take care of it from there.

26:52 So it's got an S3 backup, but it's really just using a CDN.

26:56 And putting your site entirely on a CDN is groundbreaking.

27:02 You know, when I figured out that I could do that, I was all about it.

27:07 It's blazing fast now and I don't have to worry.

27:11 It's super easy.

27:12 There's no denial of service.

27:14 But I guess another thing that's pretty interesting about that is like if I open up my micro WSGI log, which is the worker processes for my websites, and I watch them.

27:26 A lot of times people are coming and requesting things that I want them to request, but, you know, periodically they'll be going to wp-login.php or some other malicious thing.

27:39 My site is not built in WordPress.

27:40 It's Python, so I don't really care.

27:42 Like I just like block those people.

27:44 But it's very clear that there's like a continuous sort of low burn attack against your servers, against your web server infrastructure, and your site.

27:56 And it's super hard to like SQL inject static on a static site, right?

28:02 Exactly.

28:03 Like any of these other things.

28:04 If you have no logic backend and you have no database that's going to get compromised, then you don't have to worry.

28:10 That's right.

28:11 I mean it's down to does Cloudflare itself get – or Cloudfront itself get hacked, right?

28:16 Is that a thing that can be done?

28:18 And if it can't, then you're good.

28:20 And even if it can, it's kind of not your problem.

28:23 Yeah.

28:24 You could be defaced, but it's not like you're going to be in the news because now a million recordings from a teddy bear between kids and their teddy bear are now on the internet.

28:35 And honestly, you probably won't even be defaced.

28:38 If Cloudfront is having any sort of problem, it's probably going to affect more than just you.

28:42 Yeah, exactly.

28:43 It also is better for security because that means if any problem happens, it'll get a lot of attention and get fixed faster because the rest of the world is looking at it, not just your users.

28:56 So it's cross-platform, right?

28:57 It works like the tooling to generate the static content.

29:01 I mean obviously HTML is cross-platform, but it does take some tooling to power the CMS to generate the data files that are then built into HTML, right?

29:10 Right.

29:10 Lecter is built in Python and it runs on Linux and Macs and Windows.

29:16 It should run everywhere.

29:18 And the CMS that Lecter runs internally is just front-end content.

29:24 It's built in React.

29:25 You open up a browser and you see your CMS.

29:28 Yeah, it's pretty cool.

29:29 There's no database, but it acts like a database, right?

29:33 There's a set of files and a file folder structure, basically a markdown and then these INI files, right?

29:40 Tell us maybe a bit like at the interplay of page templates, the markdown and these like sort of definition files.

29:48 Frameworks had like Django.

29:50 And in Django, you have model files and you've got admin files and you have databases that you connect to.

29:57 And Lecter is kind of thinking that, but it's making it a lot simpler and accessible.

30:03 So instead of a models file .py and writing Python code, we have simple INI files where you can define fields and content types and page types.

30:14 And all of that data is stored in flat files on your system.

30:20 And then the templates have access to all of that content in their template context.

30:27 So you can use the templates with the Jinja tags to query for body content, for titles, for URLs or checkboxes or anything like that.

30:39 That's really, really clever.

30:40 So let me repeat this back to see if I got that right.

30:43 So we have these INI files and they define like basically what data is in a given type of page.

30:48 So you have different types of page, like blog posts, landing pages, whatever.

30:53 So like you could say a blog post contains a title, content, an author and a published date, for example.

30:58 And then you have a markdown file that has those various pieces of information entered into them.

31:06 And finally, you have a Jinja 2 template that takes that bit of information and then renders it like however you would in like a regular HTML.

31:17 It's like a dynamic HTML expression of that.

31:20 That's all pretty close, but I think you got a little bit wrong.

31:24 So the information isn't stored all in one markdown file.

31:28 It's stored in a lectroproprietary format that is just a flat file of data.

31:33 Oh, right.

31:34 But you don't see that most of the time as a user.

31:37 What you see is you interact with the CMS.

31:39 So you define the INI file, which is a model file, and then you go to the CMS and you make a new page of a certain type.

31:47 And the CMS will show you all the content fields that you need to populate.

31:51 So the published date and the author and the body content are all separate fields in the CMS.

31:58 And do they have types?

31:59 Yes.

32:00 Those fields can be of type markdown or string or date or integer or checkbox or anything like that.

32:09 So the template, you can query for the specific fields and do template logic on those fields if you want or just simply display them.

32:20 It'll render the markdown for you if the type is a markdown file or markdown content.

32:26 That's pretty cool.

32:27 Another thing that's pretty nice for large sites is dependency tracking.

32:32 Right?

32:33 So initially, like who cares?

32:36 It's just a few files.

32:37 But, you know, you could easily see over time something with a thousand pages.

32:41 Right?

32:42 Like if, in say, a bookstore, like a data-driven bookstore, you might have a landing page, a category listing page, and individual book details page.

32:55 It might be just three pages, but the data drives like thousands of distinct URLs.

32:59 In a static site generator, you literally build a thousand pages.

33:05 Right?

33:05 And then, like, generate because your database is this stuff.

33:08 So with dependency tracking, like, that could be a big deal.

33:11 Right?

33:11 So what's the story of that?

33:12 That can be a big deal.

33:14 So you're swapping out a database like Postgres for flat files, and that has certain tradeoffs.

33:21 Right?

33:22 Postgres is optimized on the file system, and it's fast.

33:27 Flat files are not optimized for size or speed, but they're much easier to read by human.

33:35 And that means you can actually version control all this.

33:39 It's not binary anymore.

33:40 You're actually storing the text from the various fields of these books or the author information or publication information.

33:49 So if I – like, maybe you change, like, the details about one book, and you want to redeploy it.

33:55 You don't want to regenerate a thousand files.

33:58 You want to just regenerate that one HTML file, right?

34:01 Right.

34:01 And that's what would be generated.

34:03 So if you're changing the information about one book, then there would be a single file that is touched that's devoted to that one book in your flat file system in Lecter.

34:13 And that would have a line change in it when you change the author information.

34:17 You're correcting a typo.

34:19 And then Lecter would notice that change and auto-rebuild the relevant HTML file for it.

34:27 And it wouldn't build all of it.

34:30 When you run Lecter server the first time, it builds all of your files.

34:33 But then it just is looking for changes.

34:35 And it builds files for anything that is touched.

34:38 That's nice.

34:39 It'll even do that, like, as you interact with them, either on the file system or through the CMS, right?

34:44 That's pretty slick.

34:45 And unless you're changing content that's actually relevant to a thousand pages, you're not going to build a thousand pages all over again.

34:51 Yeah, that's real cool.

34:52 This portion of Talk Python to Me has been brought to you by Rollbar.

34:59 One of the frustrating things about being a developer is dealing with errors.

35:02 Relying on users to report errors, digging through log files, trying to debug issues, or getting millions of alerts just flooding your inbox and ruining your day.

35:11 With Rollbar's full-stack error monitoring, you get the context, insight, and control you need to find and fix bugs faster.

35:18 Adding Rollbar to your Python app is as easy as pip install Rollbar.

35:22 You can start tracking production errors and deployments in eight minutes or less.

35:26 Are you considering self-hosting tools for security or compliance reasons?

35:30 Then you should really check out Rollbar's Compliance SaaS option.

35:34 Get advanced security features and meet compliance without the hassle of self-hosting, including HIPAA, ISO 27001, Privacy Shield, and more.

35:43 They'd love to give you a demo.

35:45 Give Rollbar a try today.

35:46 Go to talkpython.fm/Rollbar and check them out.

35:51 So it has built-in image sort of thumbnailing tools and stuff.

35:55 That's pretty nice.

35:56 It has a plug-in system.

35:58 So that sounds like you could really take sort of Lecter out of the box and then make it really adaptable to kind of the way you might with, say, a traditional data-driven app.

36:08 You can also mess with the Jinja templates, which is sort of a programmable layer as well, right?

36:14 Yes, you can do a lot with the plug-ins system, and a lot has been done.

36:18 We've got more than a handful of plug-ins on our website.

36:22 There are plug-ins that change functionality inside your Jinja templates.

36:27 There's plug-ins that change how your markdown is rendered.

36:31 So if you want special formatting and you want to enable certain niceties in the markdown.

36:36 Like GitHub flavor table sort of thing?

36:38 Yeah, you can change the renderers or the lecters in the markdown.

36:44 You can add classes.

36:46 You can have special markdown syntax that's your own and have the rendered markdown use custom HTML classes.

36:56 There's admonitions.

36:59 There are plug-ins that allow you to deploy to various different places.

37:05 Like the S3 deploy isn't built in in Lecter.

37:08 That's provided by a plug-in as opposed to GitHub page deploys, which is native.

37:14 Oh, that's pretty sweet.

37:15 So you can actually go in there and sort of tell the plug-in your API key and then just run a command, and then you have a new version online?

37:24 That's right, and you can hook into – so you can write a plug-in to deploy to anywhere you like.

37:29 That's awesome.

37:30 It also has a Python API.

37:33 So is that just like a different angle to get in there instead of writing a plug-in, maybe from the outside instead of the inside?

37:41 Or like what's an example of what I might do with the API or what I could do?

37:46 The first common use of the API is within the plug-ins itself.

37:49 It's telling you how to access every part of the Lecter system through a plug-in.

37:54 So the plug-ins have various events, various event hooks inside the Lecter code that they respond to.

38:02 So when something happens, it trips an event, and any plug-in listening on that event can have the opportunity to do something.

38:09 But that plug-in has access to all of the Lecter source files in Python, so it can import everything and change anything.

38:19 I see.

38:20 That's pretty cool.

38:20 So maybe some part – let's say, for an example, like part of your site depends upon data you might get from an API or something like that, like a web service, right, that is not part of your site.

38:34 Maybe at build time, you just like go and hit that, refresh it, and then dump it in there and render it.

38:40 So it's kind of live.

38:41 It's sort of cached from the moment of generation anyway.

38:44 Yes, you could do that, definitely.

38:45 You could do that.

38:47 You could change the types that are in Lecter.

38:50 You could add a content type that's entirely new, a field type.

38:54 You could generate entirely different kinds of pages.

38:58 There are plug-ins that add template functionality to allow Atom feeds and Discus really easily.

39:07 Right, right.

39:07 Discus is pretty nice.

39:09 And, yeah, I guess you could even, like, regenerate, like, an RSS file sort of thing, right, say, for blogs or a store.

39:17 You want to have the new items or whatever.

39:18 Yes, there is an RSS Atom feed plug-in.

39:22 Yeah, very cool.

39:22 So one of the areas that I was – when I was playing with Lecter, I'm like, this thing is really nice.

39:29 One thing I would like to see when I was playing with it is maybe ways to configure how it looks, right?

39:35 Because it comes out and it looks like it looks.

39:37 But I'm like, oh, can I, like – you know, one of the things I love about Bootstrap is, like, themes, right?

39:43 I can go to, like, say, Wrap Bootstrap or something like that and go, here's a whole bunch of stuff.

39:48 I'm not a web designer, but that looks really close to what I want.

39:51 Let's see if I can hack that into the shape I wanted, you know?

39:54 What's the story around themes for what you guys are doing?

39:56 Themes are really new in Lecter, actually.

39:58 They did not exist prior to a few months ago.

40:01 But as of Lecter 3.1, which came out in January or February, there is now theming functionality in Lecter.

40:09 There's not a lot of themes available yet, but they're growing in numbers slowly.

40:15 So people should go ahead and try this out and make some and publish them for us.

40:20 We'll add them to our list.

40:21 Yeah, that sounds really good.

40:22 So themes allow you to easily modify the look and feel of your website, of course.

40:29 But in Lecter, they can do more than that.

40:32 They can add content type.

40:33 You can have models in your themes, even.

40:36 I see.

40:37 So if I wanted to have a theme for, like, a photography store, I could have, like, a photo model type that has, like, the picture and the little copyright information and the date and things like that.

40:51 Yes, absolutely.

40:52 And as you would expect with a theme, anything can be overwritten or extended, too.

40:57 So when you're using a theme, like a photography theme, you could easily add your own models for videos if you also do videography.

41:06 I see.

41:06 If you decide you don't like after using the theme for a while, you don't like the model and you want to extend it, you can do that, too.

41:13 Okay.

41:14 Yeah, that sounds really nice.

41:15 So when I went through and sort of created this little playground site that I was playing with, I went through and I installed Lecter.

41:23 I did that off of GitHub.

41:24 And then I typed Lecter Quick Start, and I got the site, and I played with it.

41:30 Like, how would I incorporate themes into that?

41:32 Like, how do I know what themes are there?

41:34 Is there a way to type, like, quick start photography one or whatever?

41:38 There is not a command line tool to just grab the theme so easily yet, but we've got some issues on the GitHub for making that.

41:50 Right now, what you would have to do is, where you have your Lecter code, you make a themes directory, and in that themes directory, you put any themes that you like.

42:00 And the themes that exist right now are in their own repository on GitHub, Lecter Themes.

42:06 So you can check those out and download or clone any of those, and they will be picked up by your Quick Start.

42:15 You'll have to, the Quick Start provides its own default styling and templates and models.

42:22 So when you add the theme, you'll have to remove some of the ones that Quick Start added because they will be overwriting the theme.

42:30 Right.

42:31 Because that's a feature of the themes is that they're overwritable.

42:34 Right, right.

42:35 Well, that sounds pretty cool.

42:36 I think maybe a really cool plugin would be, like, list all the themes, activate the themes.

42:42 Who knows?

42:44 Would it be possible to write one that did that?

42:46 It seems like it would.

42:47 It would.

42:47 Though that sounds like such a good feature.

42:49 I'd like it in Electric Core.

42:51 Yeah.

42:53 Yeah, that's true.

42:54 It should just be built in, right?

42:55 Maybe some experimental stuff could be done as a plugin that could be brought in, right?

43:00 Kind of like maybe Python standard library style.

43:03 Yeah, it could be.

43:04 But definitely, theming is new, but it's very exciting.

43:07 So I'm trying to push the themes because I think that'll make people's lives a lot easier.

43:12 Yeah, I think it's really, really great.

43:14 And it definitely could open up sort of like a way for people to reuse the design of sites they like.

43:21 There is a showcase, right, at getlector.com slash showcase of people.

43:26 Yes.

43:27 Or sites that people have created, which is pretty cool.

43:29 A lot of them seem to be created by Armin Roeniger of Flask fame.

43:34 Like, he was involved in the early days of this project.

43:37 Is that right?

43:37 Yes, absolutely.

43:38 Armin is the creator of Lecter.

43:40 Yeah, that's kind of what I thought, but I wasn't 100% sure.

43:42 Armin is the creator of all the Palettes projects.

43:46 And he's the creator of Jinja and WorkZoog and Flask.

43:50 So he's done a lot.

43:53 And Lecter uses many of those tools and wraps them up nicely.

43:57 Yeah, when I typed Lecter server, I got localhost 5000.

44:01 I'm like, I see, Flask.

44:02 Okay.

44:03 Yep.

44:04 Absolutely.

44:05 Flask is what's driving the CMS.

44:08 So it's a Flask server using a bunch of React.

44:11 Okay.

44:11 Nice.

44:12 And the showcase, since he made Lecter and he made GetLecter's original website, the first few pieces of the showcase are his websites.

44:25 But to scroll down, you can see others.

44:28 One that I really love is a PyCon website that is on the showcase.

44:35 It's a beautiful example of a single page website.

44:40 Yeah, PyCon Philippines.

44:41 Yeah.

44:41 Yep.

44:42 Nice.

44:43 Yeah, that's a good looking site.

44:44 Very, very cool.

44:45 So speaking of single page, like maybe the last thing we'll have time to touch on is you have a bunch of guides.

44:52 So there's a quick starter, but it's like, all right, well, I want to create something that has categories or discus things or how do I deal with error pages, right?

45:00 So you have a bunch of guides that go through those types of things.

45:02 Do you want to tell people a bit about those?

45:04 Categories, for instance, is a really handy guide because it's a very commonly wanted feature.

45:09 You want to be able to have projects or pages that are cross-linked somehow by certain categories.

45:17 Right.

45:18 It's one thing if it had like one category, you just put it like in that subfolder and it's fine or something.

45:23 Right.

45:23 But if it could be like in science and engineering, like, oh boy, now you're in trouble, right?

45:27 Right.

45:27 Exactly.

45:28 Because you could manually create all of this and make them all separate pages, but that's not using a lot of the power that's available to you.

45:36 Right.

45:36 And data duplication as well.

45:38 And though Lecter can be used in a very simple fashion, some of the power is a little tricky.

45:45 So we've got some guides to help sort that out for you.

45:49 So you don't have to create all of the Gingelogic and the macros in your templates to figure out how to appropriately use the categories and how to set up the models so that you have the categories functionality.

46:02 Yeah, that's really cool.

46:03 Yeah.

46:04 So you've got the distance comments, the error pages, which, you know, is always a nice thing to have.

46:08 Pagination.

46:10 Yeah.

46:11 Pagination is critical, especially if you have a blog.

46:15 There's a guide for single page apps, which is really nice because if you have in mind a static site generator building an HTML file for every page that you have and every page is a different topic, then it might not be obvious to you how to concatenate or combine all of that content into a single page, which is what you really want sometimes.

46:37 Yeah, yeah.

46:37 Like, just show me the latest flat down the list in order, things like that.

46:41 Sitemap is also sitemap.xml.

46:45 We talked about the SEO benefits of static sites.

46:48 Like, here's a big one.

46:49 Yes.

46:50 So there's a quick guide to get that up and running, which is really handy.

46:54 There's also a Webpack guide.

46:57 So it can get you started integrating some of the fanciness of the rich JavaScript tooling.

47:06 Webpack does all sorts of interesting things like SCSS or less or bundling or a whole bunch of those types of things if you want them, right?

47:15 Yes.

47:16 You could even make a fairly complicated React app on top of Lector if you wanted.

47:22 Yeah, that's cool.

47:22 Yeah, that's cool.

47:23 I've looked at using Webpack for my sites, and I decided I would rather have something simpler.

47:29 And I just use, like, super aggressive caching.

47:31 Like, cache this for a year.

47:33 Everything that's static, just cache it for a year.

47:36 So the very first time, you might hit four JavaScript files and three CSS files, but you'll never get them again.

47:42 So, like, I'm not going to go to the layers of trying to regenerate that stuff.

47:47 I know a lot of people make use of Webpack, and it works for them.

47:50 Yep, and there's a lot of Webpack functionality around modifying your build system, too, so you can minimize all of your content.

47:58 We were talking before about minimizing even a static site.

48:01 So a lot of that can be done with Webpack or Browserify or Grunt or anything like that.

48:06 So where does continuous integration fit into this whole story of static sites in Lector?

48:11 Like, does it make even sense to set up continuous integration and have, like, something like Travis CI or various, you know, servers, like, looking at your possibly your Git history and checking those out and verifying everything, like, compiles correctly with Lector?

48:29 You can wrap up tests in Travis, and you can automate builds with Travis.

48:35 Our own website is actually done like that.

48:37 So every time we push a commit to the Lector website repository on GitHub, Travis goes, and it builds all of that, and if it's good, then it deploys it.

48:47 So that's really handy.

48:49 Does it just use, like, the S3 plugin and just, like, run that command on successful build?

48:53 Basically.

48:54 It's not using S3, but it is deploying on the successful build.

48:57 Nice.

48:58 Okay.

48:58 Well, that's really, really cool.

48:59 Yeah, and you can automate all of that with other things, too.

49:02 It doesn't have to be Travis.

49:03 You can make it on a cron job if you wanted.

49:05 Right.

49:06 Anything like that.

49:06 Yes, but it doesn't, I guess it doesn't depend as much.

49:09 It's not like there's not as much logic, but I guess you could still screw up one of your Gingita templates or something like that, right?

49:18 So you might want to test.

49:19 Yes, and that's not too hard to do.

49:22 Lector is appropriately verbose, I think, in how it outputs information.

49:27 It'll tell you when it's building all the web pages, and it'll tell you their success or failure.

49:33 So you can look out for those basic failures.

49:36 So you can test for the page building successfully.

49:40 That won't, of course, test if the content is correct.

49:44 So if you made some typos, then you'll still have to catch that by hand.

49:47 Yes.

49:48 Maybe something with Selenium against, like, I don't know, something local.

49:52 Who knows?

49:53 But a build server is not going to do it, for sure.

49:55 Nice.

49:56 To me, it sounds like Lector fills a pretty interesting middle ground, I guess, between full stack stuff and static sites.

50:05 Having models is a game changer for a static site, and the CMS baked in is a really easy way to use it.

50:14 So you have a lot of the features that, for instance, Django would have, except for the actual backend processing, which you often don't need.

50:24 But that doesn't mean you don't want models, you don't want to define different content types and different data structures.

50:30 You just don't need the additional complexity of actually using Postgres or having backend Python.

50:37 You don't need the servers and the databases and all of that comes with taking those on board.

50:41 Those are more like puppies, right?

50:43 Once you get them, you have to raise them and care for them continuously, basically.

50:49 Oh, yes.

50:50 And there's loads of headache that you avoid in not having to do that, too.

50:54 You don't have to manage your own CI CD.

50:56 It becomes really simple, and you don't have to worry about security as much, which we talked about.

51:01 Yeah.

51:01 And it's blazing fast on top of it.

51:02 Scalability, distribution denial of service, these are not real issues, yeah.

51:06 Right.

51:07 You let the CDN handle that.

51:08 Yeah, exactly.

51:09 Very cool.

51:10 All right.

51:10 So let's leave it there for Lector, but I'll ask you the two final questions before I let you out of here.

51:16 So if you're going to work on some Python code, what editor do you use?

51:21 Four years, I've been an Emacs user.

51:23 Oh, right on.

51:24 I've got my own .emacs store in a Git repo that I can't live without.

51:29 Nice.

51:29 So it's right there.

51:30 Anytime you got to check it out, you're all good, right?

51:32 Yep.

51:33 .emacs.d.

51:34 Yeah, perfect.

51:35 And then notable PyPI package.

51:37 Obviously, there's Lector, right, which is great, but what else?

51:41 A personal favorite of mine for DevOps is SaltStack.

51:45 I've been doing a lot of DevOps at Terminal Labs the last couple of years, and SaltStack is enormously feature-rich.

51:52 It can do almost everything I can think of.

51:54 And we've got our own open source project named Rambo, which is built on top of SaltStack partially to make DevOps even easier.

52:04 We're building it as a provider-agnostic provisioning framework.

52:08 Oh, nice.

52:10 So Rambo makes great use of Vagrant and SaltStack to make a lot of things a lot easier.

52:15 So it helps get up and running with a lot of things pretty fast.

52:18 The other thing, which isn't exactly a pit package that I really want to plug, is Kondo.

52:22 Are you familiar with Kondo?

52:24 Yeah, Kondo's awesome, especially if you're trying to do something on Windows involving data science and vcvaralls.bat or something like that, right?

52:34 Just basically, pip installing a lot of the data science tooling requires funky compilers that are not easily accessible on Windows.

52:42 And this pre-builds it, and you kind of get everything pre-packaged and ready to roll, right?

52:46 Absolutely.

52:47 Even outside of data science and machine learning, but just normal Python development, Kondo has saved my butt more than once.

52:55 You never know.

52:56 It always surprises me when I try and pip install something that has some C dependency that I didn't have on my system that it doesn't work.

53:05 So I would either have to Google around and fight it for an hour or two trying to figure out how to install it, or use Kondo and it just works.

53:12 Kondo install.

53:13 Forget this thing.

53:14 We're out of here.

53:15 That's cool.

53:15 Yeah, really nice.

53:16 Really nice.

53:17 All right.

53:18 Final call to action.

53:19 People are all excited about static sites, about Lecter.

53:22 What can they do?

53:23 Go check it out, firstly.

53:24 Try it out.

53:26 Hopefully you'll love it.

53:27 If you do, please, if you're a Python developer, try contributing.

53:30 We have an active Gitter, and I'm pretty active in the community.

53:34 I'll try to respond to anything.

53:36 Yeah, I think that's how I actually got in touch with you is I found you on the Gitter channel.

53:39 Yeah, so that was cool.

53:40 Right.

53:40 Well, I would love to see more plugins being made.

53:43 You can do anything with a plugin, and we also would love to see more themes.

53:46 So if you are a theme developer and even not a Python developer, you want to spread your theme around to the Lecter world instead of just Hugo or WordPress, then come on over.

53:57 Yeah, that sounds awesome.

53:58 All right.

53:59 Well, I think Lecter is pretty cool.

54:00 People should check it out.

54:01 And Joseph, thanks for being on the show.

54:03 It was great to talk about all this stuff with you.

54:05 Thank you.

54:06 This has been another episode of Talk Python to Me.

54:10 Our guest on this episode has been Joseph Nix, and the episode was brought to you by Linode and Rollbar.

54:16 Linode is bulletproof hosting for whatever you're building with Python.

54:20 Get four months free at talkpython.fm/Linode.

54:24 That's L-I-N-O-D-E.

54:26 Rollbar takes the pain out of errors.

54:29 They give you the context and insight you need to quickly locate and fix errors that might have gone unnoticed

54:35 until your users complain, of course.

54:37 As Talk Python to Me listeners, track a ridiculous number of errors for free at rollbar.com slash Talk Python to Me.

54:44 Want to level up your Python?

54:45 If you're just getting started, try my Python jumpstart by building 10 apps or our brand new 100 days of code in Python.

54:53 And if you're interested in more than one course, be sure to check out the Everything Bundle.

54:56 It's like a subscription that never expires.

54:59 Be sure to subscribe to the show.

55:01 Open your favorite podcatcher and search for Python.

55:03 We should be right at the top.

55:04 You can also find the iTunes feed at /itunes, Google Play feed at /play,

55:10 and direct RSS feed at /rss on talkpython.fm.

55:14 This is your host, Michael Kennedy.

55:15 Thanks so much for listening.

55:17 I really appreciate it.

55:18 Now get out there and write some Python code.

55:20 Thank you.

Back to show page
Talk Python's Mastodon Michael Kennedy's Mastodon