cybrkyd

PaPy - a Python static site generator

 Fri, 03 Oct 2025 07:48 UTC
PaPy - a Python static site generator
Image: CC BY 4.0 by cybrkyd

PaPy has been completed. It is live. I have managed to get it to reproduce my blog as it was output by Hugo.

I’ve changed a few things around (as I always do) but overall, I am happy with the performance and the outcome.

The basic blog generation was simple enough; the challenges came with trying to add back my search functionality and my site stats. By using {% for %} loops exclusively, I sort-of knew that I would run into a few constraints along the way, but that was part of the fun. The fun lay in finding the workaround and punching through the problems.

Search

I opted to continue using lunar.js. It is light-weight and does the job I need it to do. Enough said.

Stats

I went through a few trial-and-error solutions for this one. Hugo was capable of generating all three of the statistics which I need: (1) total number of posts, (2) total word count and, (3) total lines of code. Whilst Python is capable, I had a struggle here with writing a fast calculation. Each attempt would result in a full second or more being added to site generation, so initially I went with a bash script.

Eventually, I did the walk away technique I employed when I ran into the issue of how to move my archive HTML from the script to the template. A few days later, the solution hit me. I was trying to run all three together and I was making a hash of it. I split them up and worked on them individually.

Once I had the three functions working well separately and super fast, I simply chained them together and presto! I get the same stats output as before and all I add is 0.2 seconds to the generation time.

Overall

That is a good result. I’m currently outputting my full site in 661ms versus Hugo’s 688ms on the same machine with the same build.

PaPy does not yet cache between builds, however. This means, it generates everything every time. I know, it is not a very efficient way to operate, but there is a method to my madness.

I do not want a cache, I don’t think. Even if I get to 10,000 posts, what would prevent PaPy from being able to output everything each and every build? The only thing there is to lose is time.

Maybe one to think about for the future but right now, I’m kicking Hugo’s behind on the site generation time, even if it is only by 27ms. When I start getting to maybe a 10-second generation, I might think about caching.

The reason why I did not include caching is because I would need to have somewhere to store it. And that would cause all sorts of problems, for example, the one that immediately comes to mind is portability.

I can copy my entire site folder from PC 1 to PC 2 and I can easily do that with the cache. But I worry too much about how to store that cache as well. Cache (to me) has always been easily corruptible, so I tend to avoid it where I can. Maybe that’s just my biased way of looking at this but hey, we are doing just fine right now without cache. So let’s not make this too complicated, shall we?

What else? Besides the challenge of the archive HTML move to the template, I did the same with the tags HTML. It was in the script — heaven knows why I did it this way to begin with — but was much easier to move as I had the experience of doing the archive change.

300 lines??

I concede: my initial estimate of 300 lines was way off, 50% way off! That’s terrible prediction on my part. We are now sitting on about 700 lines, which includes my double-line separation of functions. In my defence though, at 300 lines, I had a fully functional site generator; it just wasn’t very… let’s say… feature-heavy!

Overall, I’m happy with this “weekend” project (that actually took an entire month almost). But I got there. It was a nice push to dust off the old brain cells and make something with my own hands. Something I can fix when it breaks; something I did for me (and anyone else, if they want it), and something that, when I think “Ooh! I wish I had this on my blog”, I can actually just add it myself without reaching out to someone else to ask how to do it because I can’t wrap my head around Go.

It’s liberating. Especially knowing that I’m no Python expert, not a professional developer, and have never had any formal education in Python. I’m self-taught by a lot of trial and error, the Cybrkyd way! And I’ll do it all over again. Toodle-pip!

»
Tagged in: #python #PaPy

Visitors: Loading...