Posts tagged with "Python"

BlogMore v2.30.0

2 min read; 9 GFI

BlogMore has been bumped to v2.30.0. This release is pretty heavy on new features, but it does also include one small accessibility tweak too. While looking through some of the neutral feedback from PageSpeed Insights I noticed it mentioned that in some cases I had a category and a tag linked on the same page, where the text of the link was the same. That's pretty common on my blog. For many of the categories (especially things like AI, Coding, Emacs, Python, etc.) I'll also have a corresponding tag. The idea is that categories are essentially sub-blogs within the blog, whereas tags characterise a post.

Given that the same text for different purposes doesn't give much context from an accessibility point of view I've added appropriate aria-label attributes to differentiate these links.

Now for the new features.

The first is another "discover other posts" type feature, that might encourage a reader to venture further into a blog. While BlogMore does support backlinks (as was added back in v2.16.0), I have been thinking that a "related posts" feature would be interesting to add. So now it's added. This is enabled with the with_related configuration option (or the --with-related command line switch) and provides control over how many related posts are shown; the default is three.

Example related posts

Because calculating the best related posts, for every post, will cost in time and memory, some control over how "accurate" the hits are is given. You're also not stuck with "Related Posts" as the title either.

Using a different title

The rest of the new features are more admin-based and are all commands on the BlogMore command line. The first is the drafts command which simply lists the filename of all the posts that are in a draft state.

The second new command is links dump. This is a utility command for dumping a CSV list of all the external links that can be found in your posts, along with the filename of the post the link was found in. This could be useful for all sorts of things; for example writing your own external link statistics tool, or perhaps writing your own external link checker.

Talking of external link checkers: I've also added links check. This is a bit experimental, but is intended to be a simple checker of all the external links, seeing if they're still out there. By default, when run, it'll check every link it finds and, if there's a problem with it, it'll report the issue. There's a --verbose mode as well if you want feedback on all the links that are working.

It seems like every time I think I'm done adding features, something else is either suggested or pops into my head. I feel like I'm near the end of adding stuff now and should be getting back to refining the code.

I'm fairly sure I've said that before.

BlogMore v2.29.0

1 min read; 10 GFI

A quick update to BlogMore that stems from a couple of accessibility concerns raised when using PageSpeed Insights. While the accessibility score on pages generated by BlogMore is pretty excellent (96/100), a couple of things were highlighted that seemed worth tackling in some way.

The first was that the title bar of code blocks is rather low in contrast, especially the name of the language. This was a deliberate choice on my part; when I'd prompted Copilot to do this work some time back I'd expressly asked it to make the text "subtle". While I could have undone that, I do like how it looks and would like to retain it if possible. So, as an experiment, I've used prefers-contrast as a signal that I shouldn't do that. So now there's a bit of extra CSS under prefers-contrast: more which just uses the normal text colour for those headers.

I imagine this won't boost the score on PageSpeed Insights -- presumably it won't simulate that being used -- but I would hope it's an improvement for those who do need the extra contrast.

The other issue that was flagged up was the lack of an underline on the email address link in the comment-via-email invitation box (the optional feature I added back in v2.17.0). That one was an easy fix. There was no reason to avoid an underline on the link, so I added one.

BlogMore v2.28.0

1 min read; 8 GFI

I've just released BlogMore v2.28.0. This release has some small improvements to the JSON-LD structured data that was added in the last release, and also adds support for actually showing author names on posts.

On the latter point first: I only ever really created BlogMore for myself, thinking that perhaps some other folk might use it at some point. All along, though, I had it in mind that it would only ever be used to create a site where there was a single author. Despite this, though, I'd added support for setting the author per-post, and this was reflected in the RSS and Atom feeds.

But I'd never added support for showing the author in posts.

So this release adds that feature. I've tried to add full control, with settings that let you turn on/off showing the author blog-wide, as well as providing control per-post. Also, as well as setting the default author for a blog, and being able to set the author for a specific post, you can do the same for an author's URL (setting it blog-wide and per post).

Obviously, when the author is shown, if a URL can be worked out (the one local to the post is chosen first, then the blog-wide default if one isn't set for the post), the author's name links to their URL.

The JSON-LD changes are a couple of small improvements to the content. The author data adds a url property (following the same rules mentioned above) and the image property for a post will fall back to the site logo (if one is set) when there is no cover.

BlogMore v2.27.0

1 min read; 13 GFI

Much like the last two releases of BlogMore, this is another that has ended up being on the theme of improving or adorning the generated HTML.

One change in the last release resulted in another HTML validator warning, and so that's cleaned up here (the removal of the h2 elements from the sidebar meant it no longer made sense for it to be a section, so I've turned it into a div).

On top of that, I've also decided to dip my toe into adding more "microformat" type things to the generated code. This release adds things like JSON-LD structured data and Microformats2 semantic markup, where appropriate. I've also updated all of the "socials" links that appear in the sidebar to ensure they're marked up as rel="me".

Given that this is a bit of an experiment, expect to see some tweaks and changes as I roll this out on this blog and then check and test the result. This is a useful learning exercise for me.

BlogMore v2.26.0

1 min read; 11 GFI

The previous release of BlogMore had some work that improved the HTML, ensuring that the HTML validator was happy with the generated code. Yesterday evening I ran it over more of the pages, and found a couple more things that made sense to address.

So v2.26.0 takes this a little further and tries to clean more things up. Changes include:

  • The comment email invitation box is now created with a div rather than a section, resolving a validation error about there being no h2 or similar inside the section (because we don't need any kind of heading in there).
  • Cleaned up an error relating to the misuse of an aria-label in the graph page.
  • Cleaned up an error relating to the misuse of an aria-label in the stats page.
  • Removed the h2 elements from the sidebar, making them into divs with the same style. This leaves headings as something that will only appear in the main body of any page or post.
  • Added some heading-demoting to the rendering of posts so that the heading structure of any given post is retained when it's part of any of the archive-style pages (date archives, category archives, tag archives, etc).

While not all of the above were being reported as validation errors, all of them should result in HTML that better fits what I'd want in the first place.

BlogMore v2.25.0

2 min read; 9 GFI

Following on from the previous release, which was all about trying to get a big PageSpeed Insights win through image optimisation, I'm chasing some more validation from that site by trying to squeeze just a little more performance out of the code that BlogMore generates.

BlogMore v2.25.0 has the following changes to allow tinkering in ways that might speed things up a touch, depending on the nature of the blog:

CSS bundling -- Every page generated by BlogMore pulls in at least these three CSS files: style.css, code.css and fontawesome.css (or their minified versions if minify_css is turned on). While this separation of concerns sits well with me, while it feels like the elegant way of doing things, there is the issue that it requires 3 trips back to the server to get base styling for any given page1.

So with this new version, if you set bundle_css to true, those three files are included and delivered as a single bundle.css (or bundle.min.css). This saves a couple of requests.

Theme helper inlining -- the lesser of the two main changes. There is some JavaScript that's part of each page that helps with theme switching and also provides the code to toggle the header display on mobile-sized screens. It's not a lot of code, but it is another file that has to be fetched. If inline_theme_js is set to true, this code will be included in the <head> of every single page generated for the site.

I suspect I'm going to leave this one off, but it's there if it's helpful to anyone (and also does let me experiment more with PageSpeed measurements).

Optimised logo -- one image that got left out of the work to optimise images was the site logo. While an optimised version of the image was created, no HTML was generated to make use of it. With this release, if optimise_images is true, <picture> will be used for this too.

With those shameless performance-measurement changes aside, there are a couple more changes in this release. The first is that the markup for the site title (that appears below the logo, if you have one) has been changed away from using a <h1> tag. The SEO gods frown on multiple <h1>s on a page and given the "main" title of any page is also a <h1>, this meant there were always 2 such tags. Now just the main title will be marked up this way; the site title becomes a <div> with appropriate styling to maintain the existing look.

Finally, this release fixes a small bug in the search index. It was being created with escaped HTML entities in any text that came out of fenced code blocks. From now on any text that goes into the search index is unescaped.

As always: if a blog-oriented static site generator that is all about Markdown sounds like your thing, check out the installation instructions and give it a go.


  1. Yes, of course the client-side cache makes this moot after the first page is loaded. All of this is about making that first load faster, and so appeasing the PageSpeed Insights gods. ↩

OldNews v1.4.2

1 min read; 10 GFI

OldNews

I've made a minor bump to OldNews, my terminal-based client for TheOldReader. There's no significant change in this release, but it does change the dependency on html-to-markdown.

Since I initially released the application, this library seems to have been through a couple of significant changes, and not every breaking change seems to have resulted in a major version bump. OldNews doesn't pin this dependency to a major version (I try not to, only ever setting lower-bounds for dependencies where possible), so it's fair that a change there can break things. I also think it's fair to hope that minor version changes won't cause trouble.

Recently, I've seen the library update with a minor version change and it's flat-out caused runtime errors, either because the API has changed, or because of an error being thrown by legitimate use of the API.

Most recently, such an error happened, and was fixed by the time I noticed it, but the release that was made never made it up to PyPI. This left OldNews stuck not working. Because of this I had to pin the library to an earlier version.

It's now been updated again and PyPI is correct, so I think it's safe to relax the pin.

Fingers crossed...

BlogMore v2.24.0

3 min read; 10 GFI

Quite a few weeks ago now -- I think it was around the time I started work on blogmore.el and got the new MacBook Air -- I remember sitting in a cafe in Edinburgh and via Mastodon having a conversation with Andy about tweaking better results out of PageSpeed Insights. I seem to remember him correctly observing that one of the big hits on the performance score was the size of images, and also the format, and that some SSG engines would go to the trouble of converting to the likes of WebP and/or generating different sizes that are appropriate to different screens, that sort of thing.

I can't quite remember where we left it, but I think it was considered more work than was worth worrying about, and perhaps swapping all images on our blogs to WebP would solve most of the issues.

For a couple of different reasons, late last week, I decided it was time to play with the problem. For some reason I've been pretty cautious with this PR. I planned it out last Friday night, kicked off work on it on Saturday morning, and have then been tinkering and changing it and testing it and iterating over it all weekend. Something about the nature of the change made me want to go very slowly with this. I think it was an unease about messing with the images that would get served, the nature of the new tags that would get emitted, the fact that there would be even more HTML tinkering going on, the possible complexity of maintaining the cache... lots of things to consider and this is supposed to be a nice, simple, unfussy site generator.

Anyway, I've just released v2.24.0 with this feature added. It's off by default, and is turned on by setting optimise_images to true. Then, when you build your blog, each PNG, JPEG or WebP image will be converted into one or more WebP images stored below static/images/optimised. How many are made for each image will depend on how image_widths is set. The physical size of each image (and how the image looks) can be affected by image_quality.

This does have two very obvious effects:

  1. It will result in your generated site being quite a bit bigger, if you have lots of images.
  2. It will result in the build time taking much longer.

The first issue is something I can't do anything about; it is what it is. The second issue, however, is something that can be dealt with. Given I've just made a release that speeds up build times, this would be a huge step backwards. So with this in mind, as the optimised images are created, a cache of them is also created in BlogMore's cache directory. This, again, does mean that more space is taken on your local storage to build your site, but it also means that repeated builds will remain fast.

If you run into problems or need space back, don't forget you can easily clear the cache.

So what's the result of all of this? Is it worth the effort? Well, to be sure, before I upgraded the version of BlogMore that I build this site with, I measured its performance.

Built with BlogMore v2.23.0

After upgrading and rebuilding, here is how the same home page measures up.

Built with BlogMore v2.24.0

I was genuinely surprised by the difference. The settings I used were:

optimise_images: true
image_quality: 95

and, of course, almost all the images on this site are now WebP anyway. I think I was expecting it to have a small impact, but even having those WebP images turned into stepped sizes seems to have a very measurable effect.

I'm going to be keeping a close eye on how this works for the next few days. As I say, I've tested this as much as possible and gone over the code as carefully as time has allowed. If this feature does break something I hadn't anticipated I can always just turn it off again anyway. Meanwhile though, the improvement on mobile does seem genuinely worth it.

Gemini CLI vs GitHub Copilot (the result)

4 min read; 11 GFI

Following on from this morning's initial experiment, I think I'm settling on a winner. Rather than be annoying and have you scroll to the bottom to find out: it's Gemini CLI. Here's how I found the process played out, and why I'm settling for one over the other.


Gemini CLIΒΆ

Initially this was an absolute mess. After letting it initially work on the problem, the resulting code didn't even really run. The first go, and the three follow-up prompt/result cycles that followed, all resulted in code that had runtime errors. I'm pretty sure it didn't even bother to try and do any adequate testing. This is odd given I've generally seen it do an okay job when it comes to writing and running tests.

Once I had the code in a stable state, with all type checking, linting and testing passing, it still didn't work. No matter how I tried to use the new facility it just didn't make a difference. No images were optimised. In the end I dived into the code, with the help of its attempt at debugging (it added print calls to try and get to the bottom of things -- how very human!), diagnosed what I thought was the issue (it was looking in the wrong location for the files to optimise), told it my hypothesis and let it check if I was right. It concluded I was and fixed the problem.

Since then I've had a working implementation of the initial plan.

Once that was in place it's been a pretty smooth journey. I've asked it questions about the implementation, had my concerns set to rest, had some concerns addressed and fixed, improved some things here and there, added new features, etc.

All of this has left me with 18% of my daily quota used up. While I think this is the highest I've ever got while using Gemini CLI, it still feels like I got a lot of things done for not a lot of quota use.

GitHub CopilotΒΆ

Initially I thought this had managed to one-shot the problem. Once it had finished its initial work the code ran without incident and produced all the optimised files. Or so I thought. Doing a little more testing, though, it became clear it was only optimising a subset of the images and it didn't seem to be producing the actual HTML to use the images.

On top of this it didn't even follow the full plan that was laid out in the issue it was assigned. For example: once I'd got it doing the main part of the work, it became apparent that it had pretty much ignored the whole idea of using a cache to speed this process up. I had to remind it to do this.

At one point I switched from the in-PR web interaction with Copilot, and used the local CLI instead. When I ran that up it warned me that I was already 50% of the way through some sort of rate limit and this wouldn't reset for another 3 hours. I think I was about 40 minutes into letting it try and do the work at this point.

After a bit more testing and follow-up prompts, I got to a point where I had something that looked like it was working; albeit in a slightly different way from how Gemini CLI did it (the Copilot approach was writing the optimised images out to the extras directory, mixing them in with my own images; Gemini opted for having a separate directory for optimised images within the static hierarchy).


At this point I will admit to not having carefully reviewed the code of either agent; that's a job still to do. But while Gemini got off to a very rocky start, with a bit of guidance it seemed to arrive at an implementation I'm happy with, and one that seems to be working as intended. While it didn't anticipate all the edge cases, when I asked about them it easily found and implemented solutions for them. Moreover, the fact that I could do all of this and confidently know the "cost" made a huge difference. Copilot seems to generally approach this like a quota or rate limit should be a lovely surprise that will destroy your flow; Gemini has it there and in front of you, all the time.

As for the general idea that I'm working on: I think I'm going to implement it. Weirdly I'm slightly nervous about building the blog such that it won't be using the images I created, but I also recognise that that's a little irrational. Meanwhile I'm very curious about the impact this might have on the PageSpeed measurement of the blog. While it's far from horrific, image size optimisation and size declaration seem to be fairly high on the things that are impacting the performance score (currently sat at 89 for the front page of the blog, as I type this).

The other thing that gives me pause for thought about merging this in, and then subsequently using it, is that I've just finished migrating all images to webp, and so saving a lot of space in the built version of the blog. Generating all the responsive sizes of the images eats that up again. With this feature off, the built version of the blog stands at about 84MB; with it on, this rises to 133MB. That extra 49MB more than eats up the 24MB saving I made earlier.

On the other hand: storage is a thing for GitHub to worry about, what I'm worrying about here, and aiming to improve, is the reader's experience.

I'm going to sit on this for a short while and play around with it, at least until I get impatient and say "what the hell" and run with it.

Gemini CLI vs GitHub Copilot (redux)

1 min read; 10 GFI

Given I'm almost certainly going to drop GitHub Copilot starting next month, I'm using Gemini CLI more and more for BlogMore. Yesterday evening, I used it to plan out an idea for a change to the application. Now that I've migrated all images to WebP, I thought it might be interesting to look at the idea of having a responsive approach to images. This is something I don't know a whole lot about (never having needed to bother with it before), but it also happens that I need to read up on this anyway for something related to the day job; given this, it felt like a good time to experiment.

Together with Gemini CLI a plan was created.

This morning, over second coffee, I've kicked off the job of implementing it and, honestly, Gemini CLI is really struggling. It "implemented" the change pretty quickly, within minutes, but it just plain didn't work. Since then I've had it iterate over the issue four times and now it's struggling to make it work at all. It's still beavering away on this as I type, and consuming daily quota at a fair rate too.

So, while I still have GitHub Copilot, this feels like a good point to play them off against each other at least one more time. Having saved the plan Gemini wrote last night as an issue, I've assigned it to Copilot (using Claude Sonnet 4.6). As I type this, I have Gemini racing to get this working in a terminal window behind Emacs, meanwhile there's Claude doing its thing in GitHub's cloud.

It'll be interesting to see if Copilot manages to one-shot this, for sure Gemini is far off a one-shot implementation.