<?xml version='1.0' encoding='UTF-8'?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>davep</title>
    <link>https://blog.davep.org</link>
    <description>Posts in category "Python" from davep</description>
    <atom:link href="https://blog.davep.org/feeds/python.rss.xml" rel="self"/>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>python-feedgen</generator>
    <language>en</language>
    <lastBuildDate>Wed, 09 Sep 2026 08:06:55 +0000</lastBuildDate>
    <item>
      <title>Wasat v1.9.0</title>
      <link>https://blog.davep.org/2026/09/05/wasat-v1-9-0.html</link>
      <description>&lt;p&gt;The &lt;a href="https://github.com/davep/rogallo/pull/417" rel="noopener noreferrer" target="_blank"&gt;work to add Titan support to
Rogallo&lt;/a&gt; is going well, and I've
been able to test it out fine on &lt;a href="gemini://bbs.geminispace.org/" rel="noopener noreferrer" target="_blank"&gt;bbs&lt;/a&gt;, doing
additions of "long text" and performing file uploads. In doing so, though, I
was reminded that there is &lt;a href="gemini://transjovian.org/titan/Edit%20Link" rel="noopener noreferrer" target="_blank"&gt;a proposed "edit" extension to
Titan&lt;/a&gt;, which is supported there
(and I believe on a couple of other capsules too). That got me thinking...&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt;
&lt;a href="https://wasat.davep.dev/changelog/#v190" rel="noopener noreferrer" target="_blank"&gt;v1.9.0&lt;/a&gt; is now available, which
adds support for this extension. Of most use is the
&lt;a href="https://wasat.davep.dev/library/uri/#wasat.uri.TitanURI.is_edit" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;is_edit&lt;/code&gt;&lt;/a&gt;
property which has been added to &lt;code&gt;TitanURI&lt;/code&gt;, giving a well-defined approach
to testing whether a Titan URI is for editing a resource. The &lt;code&gt;Client&lt;/code&gt; class
has also grown an
&lt;a href="https://wasat.davep.dev/library/client/#wasat.client.Client.edit" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;edit&lt;/code&gt;&lt;/a&gt;
method to handle the request for the raw content which will then be used as
the basis for a subsequent edit by the user, before being uploaded.&lt;/p&gt;
&lt;p&gt;All of this, of course, pushes back the work I'm doing on Rogallo, just a
little. As I said above, the Titan support is pretty much there and working,
but now I want to try and really dial it in and get it working "just so".
While the &lt;code&gt;edit&lt;/code&gt; support is probably pretty niche, it seems worth adding
and, I hope, might delight someone one day when they try it out and it "just
works".&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/09/05/wasat-v1-9-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Sat, 05 Sep 2026 08:20:48 +0100</pubDate>
    </item>
    <item>
      <title>Wasat v1.8.0</title>
      <link>https://blog.davep.org/2026/09/03/wasat-v1-8-0.html</link>
      <description>&lt;p&gt;Another quick little update to &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt;, bumping
the version to &lt;a href="https://wasat.davep.dev/changelog/#v180" rel="noopener noreferrer" target="_blank"&gt;v1.8.0&lt;/a&gt;. This
version is in support of some work I'm about to do on
&lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;: Titan support.&lt;/p&gt;
&lt;p&gt;This release adds &lt;code&gt;TitanURI&lt;/code&gt; and makes a number of changes to handle such
URIs alongside &lt;code&gt;GeminiURI&lt;/code&gt;. A lucky side-effect is that a problem was
uncovered and corrected with how Gemini URIs are sliced and diced in the
library. This first showed up for me when &lt;a href="https://github.com/davep/rogallo/issues/407" rel="noopener noreferrer" target="_blank"&gt;I was having a look at the
Scriptonite examples&lt;/a&gt;. None of
them were working for no obvious reason. Eventually it became clear that
parts of the URIs were being lost as they travelled through Wasat's code.&lt;/p&gt;
&lt;p&gt;So v1.8.0 clears up that problem (fixing the bug in Rogallo by simply
upgrading the library).&lt;/p&gt;
&lt;p&gt;As of now, I can move on to &lt;a href="https://github.com/davep/rogallo/issues/355" rel="noopener noreferrer" target="_blank"&gt;actually adding Titan
support&lt;/a&gt;.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/09/03/wasat-v1-8-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Thu, 03 Sep 2026 19:24:30 +0100</pubDate>
    </item>
    <item>
      <title>finger2gemtext - A library for converting finger responses to Gemtext</title>
      <link>https://blog.davep.org/2026/09/02/finger2gemtext-a-library-for-converting-finger-responses-to-gemtext.html</link>
      <description>&lt;p&gt;I've just released the first version of another library in the collection of
libraries that support the development of
&lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;: specifically, another one that helps
convert text in other formats into &lt;a href="https://blog.davep.org/tag/gemtext/"&gt;Gemtext&lt;/a&gt; so Rogallo's
display can be a little richer. In effect, this is a sibling to
&lt;a href="https://md2gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;md2gemtext&lt;/code&gt;&lt;/a&gt; and
&lt;a href="https://html2gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;html2gemtext&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This time it's a library to convert &lt;a href="https://blog.davep.org/tag/finger/"&gt;finger&lt;/a&gt; responses into
Gemtext, where it makes sense. For the most part, finger responses are
free-form plain text, but there are times when there's information in the
response that would be of most use if you could interact with it. For
example, if you get a user list from &lt;code&gt;plan.cat&lt;/code&gt;&lt;sup id="fnref:418-1"&gt;&lt;a class="footnote-ref" href="#fn:418-1"&gt;1&lt;/a&gt;&lt;/sup&gt;, that's a lot of data
that could be turned into &lt;code&gt;finger://&lt;/code&gt; URIs that can be subsequently
followed.&lt;/p&gt;
&lt;p&gt;With this in mind, &lt;a href="https://finger2gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;finger2gemtext&lt;/code&gt;&lt;/a&gt; can
take a body of text, look at it to see if it might be possible to convert it
to useful Gemtext, and will convert it if that's the case. Given that
there's no standard to be had here, and given that any given response could
be of any form the author desires, I'm making the conversion pretty
conservative.&lt;/p&gt;
&lt;p&gt;What I have done, though, is make it so that the conversion process can be
extended. The &lt;a href="https://finger2gemtext.davep.dev/finger2gemtext/#finger2gemtext.finger_to_gemtext" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;finger_to_gemtext&lt;/code&gt;
function&lt;/a&gt;
can be given a collection of additional filtering classes; if the built-in
classes can't find anything to convert, the additional classes get a go.
There is &lt;a href="https://finger2gemtext.davep.dev/finger2gemtext/#finger2gemtext.FingerFilter" rel="noopener noreferrer" target="_blank"&gt;a base class to inherit
from&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I've not fully planned it out yet, but the vague idea I have here is that
Rogallo could, at some point, have &lt;em&gt;"finger plugins"&lt;/em&gt; which will handle
various special cases and site-specific formats.&lt;/p&gt;
&lt;p&gt;For now, though, this gives me the basics that let me turn this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="A plain finger response" height="1632" loading="lazy" src="https://blog.davep.org/attachments/2026/09/02/plain-finger.webp#centre" width="1606" /&gt;&lt;/p&gt;
&lt;p&gt;into something where I can follow &lt;code&gt;finger://&lt;/code&gt; links without the need to
copy/paste/edit:&lt;/p&gt;
&lt;p&gt;&lt;img alt="A richer finger response" height="1632" loading="lazy" src="https://blog.davep.org/attachments/2026/09/02/rich-finger.webp#centre" width="1606" /&gt;&lt;/p&gt;
&lt;p&gt;Now I need to find a few more online finger resources that respond with
things worth making linkable...&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:418-1"&gt;
&lt;p&gt;&lt;code&gt;finger @plan.cat&lt;/code&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:418-1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/09/02/finger2gemtext-a-library-for-converting-finger-responses-to-gemtext.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>finger</category>
      <category>gemtext</category>
      <category>finger2gemtext</category>
      <category>smolweb</category>
      <pubDate>Wed, 02 Sep 2026 19:21:50 +0100</pubDate>
    </item>
    <item>
      <title>Port79 v1.1.0</title>
      <link>https://blog.davep.org/2026/09/02/port79-v1-1-0.html</link>
      <description>&lt;p&gt;A small update to &lt;a href="https://port79.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Port79&lt;/a&gt;, bumping up to
&lt;a href="https://port79.davep.dev/changelog/#v110" rel="noopener noreferrer" target="_blank"&gt;v1.1.0&lt;/a&gt;. This release adds a
&lt;code&gt;resolve&lt;/code&gt; method to the &lt;code&gt;FingerURI&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;I'm currently tweaking &lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;'s rendering of
some responses from finger services and being able to resolve URIs relative
to the underlying page is going to be very helpful.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/09/02/port79-v1-1-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>finger</category>
      <category>port79</category>
      <category>smolweb</category>
      <pubDate>Wed, 02 Sep 2026 16:39:03 +0100</pubDate>
    </item>
    <item>
      <title>Wasat v1.7.0</title>
      <link>https://blog.davep.org/2026/08/30/wasat-v1-7-0.html</link>
      <description>&lt;p&gt;A quick little update to &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt;, bumping the
version to &lt;a href="https://wasat.davep.dev/changelog/#v170" rel="noopener noreferrer" target="_blank"&gt;v1.7.0&lt;/a&gt;. In service of
a feature I'm adding to &lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;, I've added &lt;a href="https://wasat.davep.dev/library/trust/#wasat.trust.FileTrustStore.forget" rel="noopener noreferrer" target="_blank"&gt;a
&lt;code&gt;forget&lt;/code&gt;
method&lt;/a&gt;
to the trust store class, so that a certificate fingerprint for a particular
host/port combination can be forgotten.&lt;/p&gt;
&lt;p&gt;This came about because, if a fingerprint does change for a Gemini capsule,
I want a Rogallo user to be able to decide to either avoid it or forget it
and re-establish trust. While the fingerprint mismatch &lt;em&gt;should&lt;/em&gt; be a warning
to distrust the capsule, there might be a legitimate reason why the
certificate has changed, and I want to make that decision fairly
frictionless.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/30/wasat-v1-7-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Sun, 30 Aug 2026 18:44:36 +0100</pubDate>
    </item>
    <item>
      <title>A lot of stability</title>
      <link>https://blog.davep.org/2026/08/29/a-lot-of-stability.html</link>
      <description>&lt;p&gt;While it might seem that it's been pretty quiet on the
&lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt; front the past few days, I've been
doing some work on it every day. There are a lot of changes and improvements
coming. As I got the next release ready, I realised that some of the support
libraries I've built for it were stuck with 0.x versions while, at the same
time, having proven to be quite stable.&lt;/p&gt;
&lt;p&gt;So I've just made v1.0.0 updates to the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://html2gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;html2gemtext&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://md2gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;md2gemtext&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://port1900.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;port1900&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sybaritic.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;sybaritic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are no material changes in any of these releases, the only real change
being the bump to v1.0.0, and so marking them as stable and, of course,
guaranteeing that &lt;a href="https://semver.org/" rel="noopener noreferrer" target="_blank"&gt;semantic versioning&lt;/a&gt; promises are
now in place.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/29/a-lot-of-stability.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>Rogallo</category>
      <category>html2gemtext</category>
      <category>md2gemtext</category>
      <category>port1900</category>
      <category>smolweb</category>
      <category>sybaritic</category>
      <pubDate>Sat, 29 Aug 2026 10:01:35 +0100</pubDate>
    </item>
    <item>
      <title>Wasat v1.6.0</title>
      <link>https://blog.davep.org/2026/08/27/wasat-v1-6-0.html</link>
      <description>&lt;p&gt;The &lt;a href="https://github.com/davep/rogallo/pull/373" rel="noopener noreferrer" target="_blank"&gt;client certificate management
PR&lt;/a&gt; for
&lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt; is &lt;em&gt;very&lt;/em&gt; close to completion now --
although the thing has grown arms and legs and turned into a bit of a UI
overhaul&lt;sup id="fnref:444-1"&gt;&lt;a class="footnote-ref" href="#fn:444-1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Something I wanted to add was a quick and easy way for the
user to view the details of a client certificate that's being used for the
current page. Rogallo lets you do this for the server certificate, but not
the client certificate.&lt;/p&gt;
&lt;p&gt;It was at this point that I realised I'd never provided easy access to the
&lt;code&gt;ClientCertificate&lt;/code&gt; on the &lt;code&gt;Response&lt;/code&gt; object. So
&lt;a href="https://wasat.davep.dev/changelog/#v160" rel="noopener noreferrer" target="_blank"&gt;v1.6.0&lt;/a&gt; addresses this and
provides
&lt;a href="https://wasat.davep.dev/library/response/#wasat.response.Response.client_cert" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;Response.client_cert&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With this in place, I &lt;em&gt;think&lt;/em&gt; I can finally get that Rogallo PR over the
line...&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:444-1"&gt;
&lt;p&gt;Not unrelated. The UI overhaul was in support of the client certificate manager.&amp;#160;&lt;a class="footnote-backref" href="#fnref:444-1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/27/wasat-v1-6-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Thu, 27 Aug 2026 09:25:11 +0100</pubDate>
    </item>
    <item>
      <title>Wasat v1.5.0</title>
      <link>https://blog.davep.org/2026/08/25/wasat-v1-5-0.html</link>
      <description>&lt;p&gt;I'm still working on the &lt;a href="https://github.com/davep/rogallo/pull/373" rel="noopener noreferrer" target="_blank"&gt;client certificate management
PR&lt;/a&gt; for
&lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;, which, of course, heavily leans on
the API of &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt;. In most cases, I've noticed
that something I want to do in the PR can already be done, but the work to
perform the action would seem like unnecessary detail in a client
application; I want to make using Wasat as frictionless as possible.&lt;/p&gt;
&lt;p&gt;With this in mind, &lt;a href="https://wasat.davep.dev/changelog/#v150" rel="noopener noreferrer" target="_blank"&gt;v1.5.0&lt;/a&gt; adds
interfaces for exporting and importing client certificate data.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/25/wasat-v1-5-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Tue, 25 Aug 2026 08:07:57 +0100</pubDate>
    </item>
    <item>
      <title>Wasat v1.4.0</title>
      <link>https://blog.davep.org/2026/08/23/wasat-v1-4-0.html</link>
      <description>&lt;p&gt;Another bump to &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt;, this being
&lt;a href="https://wasat.davep.dev/changelog/#v140" rel="noopener noreferrer" target="_blank"&gt;v1.4.0&lt;/a&gt;. This release is in
support of some work I want to do on &lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;,
where I intend to add proper client certificate management.&lt;/p&gt;
&lt;p&gt;While Wasat provided good support for the generation, storage, and use of
client certificates, there was no real public API that would allow for the
management of those certificates. This version addresses that.&lt;/p&gt;
&lt;p&gt;Now there are methods for doing things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listing all client certificates&lt;/li&gt;
&lt;li&gt;Getting a specific certificate's details&lt;/li&gt;
&lt;li&gt;Creating a certificate&lt;/li&gt;
&lt;li&gt;Associating and disassociating a certificate with a URI&lt;/li&gt;
&lt;li&gt;Deleting a certificate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This should give me everything I need to implement a simple client
certificate user interface in Rogallo.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/23/wasat-v1-4-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Sun, 23 Aug 2026 11:14:49 +0100</pubDate>
    </item>
    <item>
      <title>BagOfStuff v2.0.0</title>
      <link>https://blog.davep.org/2026/08/20/bagofstuff-v2-0-0.html</link>
      <description>&lt;p&gt;I've just made a small update to
&lt;a href="https://bagofstuff.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;BagOfStuff&lt;/a&gt;, my little support library for
my personal Python-based FOSS projects. This release makes some more changes
to the history classes, adding an
&lt;a href="https://bagofstuff.davep.dev/library-contents/history/#bagofstuff.history.SimpleHistory.add_or_replace" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;add_or_replace&lt;/code&gt;&lt;/a&gt;
method, and also making some improvements to the type hinting by basing the
classes on
&lt;a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableSequence" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;MutableSequence&lt;/code&gt;&lt;/a&gt;
rather than
&lt;a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;Sequence&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While the history classes were originally intended to feel immutable, it's
obvious that they're really not. The idea was that stuff gets added to them,
stuff falls off the other end, and stuff might disappear depending on the
context and when stuff gets added. The general idea was that direct
manipulation was something that wouldn't happen. So I'd started out with
them inheriting from &lt;code&gt;Sequence&lt;/code&gt;, and so implying they were a read-only
interface.&lt;/p&gt;
&lt;p&gt;Given this acknowledgement, they now inherit from &lt;code&gt;MutableSequence&lt;/code&gt;. This
means that some extra (dunder) methods are added, and it also means that
some extra exceptions can be raised. For example: setting slices to
iterables &lt;em&gt;isn't&lt;/em&gt; supported and will raise a &lt;code&gt;NotImplementedError&lt;/code&gt;. Some
other slice-based operations aren't supported either.&lt;/p&gt;
&lt;p&gt;While this is close to a breaking change, it's fine for my use of this code.
However, I had to make one big breaking change: I'd written &lt;code&gt;clear&lt;/code&gt; so that
it returned &lt;code&gt;Self&lt;/code&gt;&lt;sup id="fnref:435-1"&gt;&lt;a class="footnote-ref" href="#fn:435-1"&gt;1&lt;/a&gt;&lt;/sup&gt;. The interface expected by &lt;code&gt;MutableSequence&lt;/code&gt; is one
that returns &lt;code&gt;None&lt;/code&gt;. So to strictly comply with that interface, I've changed
the return type.&lt;/p&gt;
&lt;p&gt;With this being a breaking change, I've bumped the library version to
&lt;a href="https://bagofstuff.davep.dev/changelog/#v200" rel="noopener noreferrer" target="_blank"&gt;v2.0.0&lt;/a&gt;. While it's really a
small change, and only one I'd notice, there's no getting away from the fact
that the API has changed. That deserves a major version bump.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:435-1"&gt;
&lt;p&gt;I tend to prefer that a method that might return &lt;code&gt;None&lt;/code&gt; actually
return &lt;code&gt;Self&lt;/code&gt;; it allows for chaining. I recognise that there are other
schools of thought about this in the Python world; I'm not a member of
those schools.&amp;#160;&lt;a class="footnote-backref" href="#fnref:435-1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/20/bagofstuff-v2-0-0.html</guid>
      <category>Python</category>
      <category>BagOfStuff</category>
      <category>Coding</category>
      <category>Python</category>
      <pubDate>Thu, 20 Aug 2026 10:46:16 +0100</pubDate>
    </item>
    <item>
      <title>md2gemtext - A library for converting Markdown to Gemtext</title>
      <link>https://blog.davep.org/2026/08/16/md2gemtext-a-library-for-converting-markdown-to-gemtext.html</link>
      <description>&lt;p&gt;Following on from
&lt;a href="https://blog.davep.org/2026/08/11/html2gemtext-a-simple-library-for-converting-html-to-gemtext.html"&gt;html2gemtext&lt;/a&gt;,
the inevitable has happened: I couldn't let the Markdown side of things
remain unaddressed. While &lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;
&lt;a href="https://rogallo.davep.dev/changelog/#v180" rel="noopener noreferrer" target="_blank"&gt;v1.8.0&lt;/a&gt; added some extra
rendering of Markdown to make it look more "pretty", I felt it really needed
to be handled so it had more utility. Being fully navigable, even by
keyboard, seems more important than pretty tables.&lt;/p&gt;
&lt;p&gt;So &lt;a href="https://md2gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;md2gemtext&lt;/a&gt; now exists as a library on
&lt;a href="https://blog.davep.org/tag/pypi/"&gt;PyPI&lt;/a&gt;. I have two plans for this. While I fully intend to shake
up the Markdown support in Rogallo -- either replacing the use of the
Textual Markdown widget to display it, or at least giving the user a
configuration option to decide how Markdown is displayed -- I also want to
pay some attention to my (currently rather simple) &lt;a href="gemini://tilde.team/~davep/gemlog/" rel="noopener noreferrer" target="_blank"&gt;Gemini-based
log&lt;/a&gt; and use this library to build a
tool that will convert this blog's &lt;a href="https://github.com/davep/davep.github.com/tree/main/content/posts" rel="noopener noreferrer" target="_blank"&gt;Markdown
content&lt;/a&gt;
into Gemtext that looks just how I want it.&lt;/p&gt;
&lt;p&gt;As with html2gemtext, this is an early version of this library, and I'm sure
there will be edge cases I'll have missed and will want to tidy up. But at
the moment the results are looking promising.&lt;/p&gt;
&lt;p&gt;I'm once again in a place where I'm actually half-seriously thinking that
much of what &lt;a href="https://hike.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Hike&lt;/a&gt; does could be built into
Rogallo, if I were to simply add &lt;code&gt;http(s)&lt;/code&gt; support there.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/16/md2gemtext-a-library-for-converting-markdown-to-gemtext.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>Markdown</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>gemtext</category>
      <category>md2gemtext</category>
      <category>smolweb</category>
      <pubDate>Sun, 16 Aug 2026 14:43:04 +0100</pubDate>
    </item>
    <item>
      <title>BagOfStuff v1.3.0</title>
      <link>https://blog.davep.org/2026/08/16/bagofstuff-v1-3-0.html</link>
      <description>&lt;p&gt;For a wee while now I've been trying to nail down a weirdness with the
navigation history in &lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;. I never felt it
was a difficult issue to deal with, but it was also one of those issues that
I could never obviously recreate at will, and it only seemed to happen while
I was busy working on something else.&lt;/p&gt;
&lt;p&gt;Yesterday evening &lt;a href="https://github.com/davep/rogallo/issues/290#issuecomment-5304008984" rel="noopener noreferrer" target="_blank"&gt;I finally managed to come up with a way to always
recreate
it&lt;/a&gt;
and, having done so, the solution seems pretty straightforward&lt;sup id="fnref:430-1"&gt;&lt;a class="footnote-ref" href="#fn:430-1"&gt;1&lt;/a&gt;&lt;/sup&gt;. In order
to implement the tweak I want, I need to be able to truncate the navigation
history, and of course do so in a non-destructive way.&lt;/p&gt;
&lt;p&gt;So the history classes in BagOfStuff
&lt;a href="https://bagofstuff.davep.dev/changelog/#v130" rel="noopener noreferrer" target="_blank"&gt;v1.3.0&lt;/a&gt; have grown
&lt;a href="https://bagofstuff.davep.dev/library-contents/history/#bagofstuff.history.SimpleHistory.clone" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;clone&lt;/code&gt;&lt;/a&gt;
and
&lt;a href="https://bagofstuff.davep.dev/library-contents/history/#bagofstuff.history.SimpleHistory.truncate" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;truncate&lt;/code&gt;&lt;/a&gt;
methods. This will allow me to duplicate a history, truncate it at its
current location, then save it, without affecting the working copy.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:430-1"&gt;
&lt;p&gt;Why do I feel like I'll regret saying that?&amp;#160;&lt;a class="footnote-backref" href="#fnref:430-1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/16/bagofstuff-v1-3-0.html</guid>
      <category>Python</category>
      <category>BagOfStuff</category>
      <category>Coding</category>
      <category>Python</category>
      <pubDate>Sun, 16 Aug 2026 09:05:47 +0100</pubDate>
    </item>
    <item>
      <title>Port1900 - An async Python client library for the Nex protocol</title>
      <link>https://blog.davep.org/2026/08/14/port1900-an-async-python-client-library-for-the-nex-protocol.html</link>
      <description>&lt;p&gt;It's that time again. Time to add another &lt;a href="https://blog.davep.org/tag/smolweb/"&gt;small web
protocol&lt;/a&gt; to &lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;. This time
it's one I stumbled across a few days ago: the &lt;a href="https://nightfall.city/nex/info/specification.txt" rel="noopener noreferrer" target="_blank"&gt;Nex
protocol&lt;/a&gt;. This one is
very simple and straightforward and it seemed like a shame &lt;em&gt;not&lt;/em&gt; to support
it.&lt;/p&gt;
&lt;p&gt;So, as I have with &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Gemini&lt;/a&gt;,
&lt;a href="https://sybaritic.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Spartan&lt;/a&gt;, &lt;a href="https://port70.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Gopher&lt;/a&gt;
and &lt;a href="https://port79.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Finger&lt;/a&gt;, I've added a dedicated library for
dealing with the associated URI, and to provide a client for talking to the
server.&lt;/p&gt;
&lt;p&gt;The documentation can be found on &lt;a href="https://port1900.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;the dedicated
site&lt;/a&gt;.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/14/port1900-an-async-python-client-library-for-the-nex-protocol.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Nex Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>Rogallo</category>
      <category>port1900</category>
      <category>smolweb</category>
      <pubDate>Fri, 14 Aug 2026 19:21:42 +0100</pubDate>
    </item>
    <item>
      <title>GopherMap v1.0.0</title>
      <link>https://blog.davep.org/2026/08/12/gophermap-v1-0-0.html</link>
      <description>&lt;p&gt;When I &lt;a href="https://blog.davep.org/2026/07/27/gophermap-a-simple-library-for-parsing-gopher-responses.html"&gt;first created
GopherMap&lt;/a&gt;,
I made it pretty strict about what it did and didn't consider a valid map.
Unsurprisingly, reality did what reality does and, pretty quickly, Rogallo
&lt;a href="https://github.com/davep/rogallo/discussions/241" rel="noopener noreferrer" target="_blank"&gt;met maps that didn't fit with this strict
approach&lt;/a&gt;. So &lt;a href="https://blog.davep.org/2026/07/28/gophermap-v0-2-0.html"&gt;I relaxed
things&lt;/a&gt;, accepting pretty much anything
that even vaguely looked like a Gopher map. This solved the problem.&lt;/p&gt;
&lt;p&gt;However, earlier today, &lt;a href="https://github.com/davep/rogallo/issues/327" rel="noopener noreferrer" target="_blank"&gt;I ran into a page that was obviously supposed to be
plain text, but was being displayed in part like a
map&lt;/a&gt;. The problem was my
attempt at detecting a reply from a Gopher server that looked like it
&lt;em&gt;might&lt;/em&gt; be an error. This very relaxed approach to &lt;em&gt;"this is likely some
Gopher stuff, let's accept it as such"&lt;/em&gt; meant that a text file that had a
&lt;code&gt;3&lt;/code&gt; anywhere in the first column was tripping off the &lt;em&gt;"this is likely some
Gopher stuff and it looks like there's an error in there"&lt;/em&gt; check. The
result? Treated like a Gopher map, converted into Gemtext, and displayed in
the wrong way.&lt;/p&gt;
&lt;p&gt;So... &lt;a href="https://gophermap.davep.dev/changelog/#v100" rel="noopener noreferrer" target="_blank"&gt;v1.0.0&lt;/a&gt; has been
released which adds some code to help out with this. The default parsing
still works as before, but there's now a strict mode which will raise
exceptions if some sort of significant problem is found. On top of this are
a couple of helper class methods which &lt;a href="https://gophermap.davep.dev/gophermap/#gophermap.GopherMap.is_likely_a_map" rel="noopener noreferrer" target="_blank"&gt;check if some text is likely a valid
map&lt;/a&gt;,
and &lt;a href="https://gophermap.davep.dev/gophermap/#gophermap.GopherMap.is_likely_error" rel="noopener noreferrer" target="_blank"&gt;check if some text is likely a valid map containing an
error&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With these in place, I can update Rogallo so that it's still pretty
easy-going when it comes to showing Gopher maps, but isn't quite so
laid-back when it comes to finding errors coming back from Gopher servers,
and so incorrectly rendering the result.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/12/gophermap-v1-0-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>gopher</category>
      <category>smolweb</category>
      <pubDate>Wed, 12 Aug 2026 15:55:27 +0100</pubDate>
    </item>
    <item>
      <title>html2gemtext - A simple library for converting HTML to Gemtext</title>
      <link>https://blog.davep.org/2026/08/11/html2gemtext-a-simple-library-for-converting-html-to-gemtext.html</link>
      <description>&lt;p&gt;Yesterday evening, while tinkering with
&lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;, I managed to nerd-snipe myself pretty
well. I was playing around with the idea of better presentation of some
forms of &lt;code&gt;text/*&lt;/code&gt; content. While, of course, Rogallo handles &lt;code&gt;text/gemtext&lt;/code&gt;
just fine, there are lots of other MIME types that it will show too (pretty
much all within &lt;code&gt;text/*&lt;/code&gt;). Already, if it can work out an appropriate
language, the viewer will do syntax highlighting, and this includes Markdown
files. However, &lt;a href="https://textual.textualize.io/widgets/markdown/" rel="noopener noreferrer" target="_blank"&gt;Rogallo has a full Markdown widget built right
in&lt;/a&gt; so I was experimenting
with using that as the way to show Markdown content.&lt;/p&gt;
&lt;p&gt;Nothing that clever really, all pretty obvious.&lt;/p&gt;
&lt;p&gt;But then I got to thinking... In &lt;a href="https://oldnews.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;OldNews&lt;/a&gt; I
heavily rely on
&lt;a href="https://docs.html-to-markdown.xberg.io/" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;html-to-markdown&lt;/code&gt;&lt;/a&gt;. Given I have
a Markdown viewer to hand, if the user ends up trying to look at some
&lt;code&gt;text/html&lt;/code&gt;, why not convert it over to Markdown and render it that way?
That's... doable.&lt;/p&gt;
&lt;p&gt;There are, however, some problems with this idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As useful as &lt;code&gt;html-to-markdown&lt;/code&gt; has been for OldNews, I've found it quite
  unreliable at times, with the occasional breaking change. I don't mention
  this as a negative about the project, but I don't want another one of my
  projects sitting on top of a moving target like that.&lt;/li&gt;
&lt;li&gt;Dragging in a reasonably large dependency for what's likely to be a niche
  requirement doesn't quite feel right.&lt;/li&gt;
&lt;li&gt;Textual's Markdown viewer has, to this day, one massive design flaw: links
  can't be navigated with the keyboard&lt;sup id="fnref:438-1"&gt;&lt;a class="footnote-ref" href="#fn:438-1"&gt;1&lt;/a&gt;&lt;/sup&gt;. I'm doing my absolute best to
  ensure that Rogallo is keyboard-first. Leaning on this widget for viewing
  Markdown is one thing, but leaning on the widget for other content types
  starts to erode that aim.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I did consider the idea of having this feature as an install option, so
you'd be able to install &lt;code&gt;rogallo&lt;/code&gt; and have it work as normal, or install
&lt;code&gt;rogallo[html]&lt;/code&gt; (or similar) and it would drag in the ability to render some
HTML using this pipeline.&lt;/p&gt;
&lt;p&gt;Then I realised: why target Markdown at all? I already have the code for
rendering Gemtext, and that solves the keyboard navigation of links problem.
How hard could it be to write something to convert HTML to Gemtext?&lt;/p&gt;
&lt;p&gt;Turns out, at least for the requirements I have right now, &lt;a href="https://github.com/davep/html2gemtext" rel="noopener noreferrer" target="_blank"&gt;not that
hard&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://html2gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;html2gemtext&lt;/code&gt;&lt;/a&gt; is still in its infancy,
but it's doing a passable job of turning most of the HTML I throw at it into
reasonable Gemtext. I don't doubt for a moment that there are &lt;em&gt;lots&lt;/em&gt; of
pages out there that won't turn out right -- for varied values of right --
but so far the results are readable and navigable. The plan now is to keep
improving as I run into new cases that could be handled better.&lt;/p&gt;
&lt;p&gt;While I've not built this into Rogallo just yet, I think I will make use of
it. I'm also giving serious thought to using it for &lt;a href="gemini://tilde.team/~davep/" rel="noopener noreferrer" target="_blank"&gt;my
capsule&lt;/a&gt;. Over there I'm &lt;a href="gemini://tilde.team/~davep/gemlog/" rel="noopener noreferrer" target="_blank"&gt;adding some posts
from this blog&lt;/a&gt; and &lt;code&gt;html2gemtext&lt;/code&gt; could
form the basis of a tool to help automate some of that.&lt;/p&gt;
&lt;p&gt;Right now &lt;a href="https://github.com/davep/tilde-team-capsule/blob/11a6bfa7e0ab6015471d660cacdd0287d10bd3dc/bin/borrow-from-blog" rel="noopener noreferrer" target="_blank"&gt;I'm using a script I've
written&lt;/a&gt;
that wraps &lt;a href="https://kristaps.bsd.lv/lowdown/" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;lowdown&lt;/code&gt;&lt;/a&gt; to do the Markdown
to Gemtext conversion, but the result -- as good as it is -- isn't &lt;em&gt;quite&lt;/em&gt;
what I'd like. I'm thinking I could tailor the results exactly as I want if
I go from this blog's HTML via &lt;code&gt;html2gemtext&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Or, of course, given my blog is written in Markdown, I could next tackle my
own just-how-I-need-it Markdown to Gemtext converter...&lt;/p&gt;
&lt;p&gt;As for how this new library will go into Rogallo... Using it to render HTML
that might be found kicking about in Geminispace or Gopherspace makes sense,
I think. That should be enough. It's not like I &lt;em&gt;really&lt;/em&gt; need to turn it
into an &lt;code&gt;http(s)&lt;/code&gt; browser too. Right? Right?!?&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:438-1"&gt;
&lt;p&gt;This mouse-only problem is a recurring theme in Textual.&amp;#160;&lt;a class="footnote-backref" href="#fnref:438-1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/11/html2gemtext-a-simple-library-for-converting-html-to-gemtext.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>gemtext</category>
      <category>html2gemtext</category>
      <category>smolweb</category>
      <pubDate>Tue, 11 Aug 2026 20:24:39 +0100</pubDate>
    </item>
    <item>
      <title>Sybaritic - A Spartan protocol library for Python</title>
      <link>https://blog.davep.org/2026/08/07/sybaritic-a-spartan-protocol-library-for-python.html</link>
      <description>&lt;p&gt;Now that &lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt; supports &lt;a href="https://rogallo.davep.dev/protocols/" rel="noopener noreferrer" target="_blank"&gt;multiple
protocols&lt;/a&gt;, it's tempting to add one
or two more. As of the time of writing, alongside
&lt;a href="https://rogallo.davep.dev/gemini/" rel="noopener noreferrer" target="_blank"&gt;Gemini&lt;/a&gt;, both
&lt;a href="https://rogallo.davep.dev/gopher/" rel="noopener noreferrer" target="_blank"&gt;Gopher&lt;/a&gt; and
&lt;a href="https://rogallo.davep.dev/finger/" rel="noopener noreferrer" target="_blank"&gt;Finger&lt;/a&gt; are supported. While wandering
the &lt;a href="https://blog.davep.org/tag/smolweb/"&gt;small web&lt;/a&gt;, I stumbled on &lt;a href="https://github.com/michael-lazar/spartan" rel="noopener noreferrer" target="_blank"&gt;the Spartan
protocol&lt;/a&gt;. Given its similarity to
Gemini and the fact it uses &lt;a href="https://blog.davep.org/tag/gemtext/"&gt;Gemtext&lt;/a&gt; as its main document
type, adding it to Rogallo seemed like an obvious thing to do.&lt;/p&gt;
&lt;p&gt;In aid of this, I've created &lt;a href="https://sybaritic.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Sybaritic&lt;/a&gt;. It
is, in effect, a sibling library to &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt;,
&lt;a href="https://port70.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Port70&lt;/a&gt; and &lt;a href="https://port79.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Port79&lt;/a&gt;.
As with the others, it is async-all-the-way and is designed to have a
similar API.&lt;/p&gt;
&lt;p&gt;With this in place, I can now extend Rogallo to handle &lt;code&gt;spartan://&lt;/code&gt; URIs as
first-class citizens.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/07/sybaritic-a-spartan-protocol-library-for-python.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>Rogallo</category>
      <category>Spartan Protocol</category>
      <category>smolweb</category>
      <category>sybaritic</category>
      <pubDate>Fri, 07 Aug 2026 19:27:00 +0100</pubDate>
    </item>
    <item>
      <title>Gemtext v1.1.0</title>
      <link>https://blog.davep.org/2026/08/07/gemtext-v1-1-0.html</link>
      <description>&lt;p&gt;I've released a small update to &lt;a href="https://gemtext.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Gemtext&lt;/a&gt;. At
the moment, I'm working on adding &lt;a href="https://portal.mozz.us/spartan/spartan.mozz.us/" rel="noopener noreferrer" target="_blank"&gt;Spartan
protocol&lt;/a&gt; support to
&lt;a href="https://rogallo.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Rogallo&lt;/a&gt;, and to do this I need to handle a
small extension it makes to Gemtext.&lt;/p&gt;
&lt;p&gt;While Spartan is quite different from Gemini in the underlying protocol, it
uses Gemtext as the default/standard markup language, but with one small
difference. To allow uploaded data that is initiated by the markup, rather
than by the server, there is a &lt;code&gt;=:&lt;/code&gt; line type. In some respects, this is
similar to type &lt;code&gt;7&lt;/code&gt; items in Gopher maps.&lt;/p&gt;
&lt;p&gt;Rather than spin up a whole new library just to support this one small
difference, and rather than do some special-case nonsense in Rogallo itself,
I've added optional (and turned on by default) support for &lt;code&gt;=:&lt;/code&gt;. When
encountered, this results in a
&lt;a href="https://gemtext.davep.dev/gemtext/#gemtext.SpartanPrompt" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;SpartanPrompt&lt;/code&gt;&lt;/a&gt;
object, which simply inherits from a
&lt;a href="https://gemtext.davep.dev/gemtext/#gemtext.Link" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;Link&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Any code that doesn't require this feature can turn it off with the
&lt;a href="https://gemtext.davep.dev/gemtext/#gemtext.Gemtext(with_spartan_support)" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;with_spartan_support&lt;/code&gt;
parameter&lt;/a&gt;.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/08/07/gemtext-v1-1-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Spartan Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>gemtext</category>
      <category>smolweb</category>
      <pubDate>Fri, 07 Aug 2026 16:33:03 +0100</pubDate>
    </item>
    <item>
      <title>Wasat v1.3.0</title>
      <link>https://blog.davep.org/2026/07/30/wasat-v1-3-0.html</link>
      <description>&lt;p&gt;A quick bump of &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt; to
&lt;a href="https://wasat.davep.dev/changelog/#v130" rel="noopener noreferrer" target="_blank"&gt;v1.3.0&lt;/a&gt;. This follows on from the
work &lt;a href="https://blog.davep.org/2026/07/30/wasat-v1-2-0.html"&gt;started in v1.2.0&lt;/a&gt;, improving how
hybrid mode works and also making host certificate verification information
available in the response object.&lt;/p&gt;
&lt;p&gt;The main improvement to hybrid mode is that it's now a little more
discerning about when to fall back on TOFU mode. &lt;em&gt;Only&lt;/em&gt; if the CA route
fails due to an untrusted root or a self-signed certificate does it then
fall back to TOFU; otherwise, an exception is raised.&lt;/p&gt;
&lt;p&gt;I've also added verification information -- such as the method used and the
fingerprint -- to the response object. This will be useful in
&lt;a href="https://blog.davep.org/tag/rogallo/"&gt;Rogallo&lt;/a&gt; if I want to show in the display how the current
server was verified.&lt;/p&gt;
&lt;p&gt;As a handy diagnostic tool, I've also added the verification method and the
fingerprint to the verbose output of the library's CLI command.&lt;/p&gt;
&lt;div class="highlight" data-lang="text"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ wasat --verify-mode=hybrid -v gemini://astrobotany.mozz.us/ | head -7
--- Gemini Response ---
URI: gemini://astrobotany.mozz.us/
Verification Method: ca
Certificate Fingerprint: sha256:dafe13d51b1aff133dd153c6d66a1a15761020017daa69378aef6e0eefb75474
Status: 20 (SUCCESS)
Meta: text/gemini
-----------------------

$ wasat --verify-mode=hybrid -v gemini://tilde.team/~davep/ | head -7
--- Gemini Response ---
URI: gemini://tilde.team/~davep/
Verification Method: tofu
Certificate Fingerprint: sha256:239f2642895698fbd16bd6fc59f2361caf6b7449a37d861d86936978c175bf78
Status: 20 (SUCCESS)
Meta: text/gemini; lang=en
-----------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With these changes in place, I think I'm set for making some improvements to
Rogallo relating to host certificates.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/07/30/wasat-v1-3-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Thu, 30 Jul 2026 16:04:09 +0100</pubDate>
    </item>
    <item>
      <title>Wasat v1.2.0</title>
      <link>https://blog.davep.org/2026/07/30/wasat-v1-2-0.html</link>
      <description>&lt;p&gt;I've just released &lt;a href="https://wasat.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;Wasat&lt;/a&gt;
&lt;a href="https://wasat.davep.dev/changelog/#v120" rel="noopener noreferrer" target="_blank"&gt;v1.2.0&lt;/a&gt;. This release aims to help
out with a change I want to make in &lt;a href="https://blog.davep.org/tag/rogallo/"&gt;Rogallo&lt;/a&gt; in relation to
certificate verification.&lt;/p&gt;
&lt;p&gt;The issue is that, until now, Wasat offered either &lt;code&gt;ca&lt;/code&gt; or &lt;code&gt;tofu&lt;/code&gt; as
verification modes. Meanwhile Rogallo was using &lt;code&gt;tofu&lt;/code&gt;. Long story short:
&lt;a href="https://github.com/davep/rogallo/issues/221" rel="noopener noreferrer" target="_blank"&gt;this meant that sometimes some sites looked like they were changing
fingerprint way more often than you'd
expect&lt;/a&gt;. The obvious solution
here is to first check if a site can be validated via the &lt;code&gt;ca&lt;/code&gt; route and, if
not, fall back to the &lt;code&gt;tofu&lt;/code&gt; route. This sort of change could have been made
in Rogallo itself, but it would have been inelegant. Rogallo maintains a
single Gemini client object, and the verification mode is baked in when the
object is created. To move to this &lt;em&gt;"try one way then the other"&lt;/em&gt; approach
would have meant either maintaining two instances of the object, or tearing
it down and making another each time we connected to a capsule.&lt;/p&gt;
&lt;p&gt;Nah.&lt;/p&gt;
&lt;p&gt;So the
&lt;a href="https://wasat.davep.dev/library/client/#wasat.client.Client(verify_mode)" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;verify_mode&lt;/code&gt;&lt;/a&gt;
of the
&lt;a href="https://wasat.davep.dev/library/client/#wasat.client.Client" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;Client&lt;/code&gt;&lt;/a&gt; has
grown a new option: &lt;code&gt;hybrid&lt;/code&gt;. When set to &lt;code&gt;hybrid&lt;/code&gt;, the client will do the
dance mentioned above: it will try and see if &lt;code&gt;ca&lt;/code&gt; will work and, if it
does, it will take that approach. If it fails, it will then fall back on
pure &lt;code&gt;tofu&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Out of the box, the defaults for the client are the same (it uses &lt;code&gt;ca&lt;/code&gt; by
default), and for the moment Rogallo is still hard-baked to &lt;code&gt;tofu&lt;/code&gt;; given
this, there should be no change in how things work when Wasat is updated.
Now that this is up on PyPI, I'm going to pin Rogallo's use of &lt;code&gt;wasat&lt;/code&gt; to
&lt;code&gt;&amp;gt;=1.2.0&lt;/code&gt; and then, in an update, I'll swap over to &lt;code&gt;hybrid&lt;/code&gt;. Hopefully this
will result in a smoother journey when using sites like
&lt;a href="gemini://astrobotany.mozz.us/app" rel="noopener noreferrer" target="_blank"&gt;AstroBotany&lt;/a&gt; and
&lt;a href="gemini://station.martinrue.com/" rel="noopener noreferrer" target="_blank"&gt;Station&lt;/a&gt;.&lt;/p&gt;
&lt;div class="admonition admonition-note"&gt;
&lt;div class="admonition-title"&gt;ℹ️ Note&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;While writing this, I've noticed that there's one change I still need to
make to this hybrid flow. I realised that, at the moment, &lt;em&gt;any&lt;/em&gt; kind of CA
failure will result in a fallback to TOFU. That's not ideal and needs
refining. All part of the learning process.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;p&gt;PS: If you're wondering what happened to v1.1.0 of Wasat... there wasn't
one. While preparing this release, I was also fighting with the fact that my
MX Mechanical Mini keyboard seemed to be dying (and its battery &lt;em&gt;does&lt;/em&gt; seem
to be dying) and, because of that, managed to bump the version from v1.0.1
to v1.2.0. Oh well...&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/07/30/wasat-v1-2-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>Gemini Protocol</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>smolweb</category>
      <category>wasat</category>
      <pubDate>Thu, 30 Jul 2026 08:45:09 +0100</pubDate>
    </item>
    <item>
      <title>GopherMap v0.2.0</title>
      <link>https://blog.davep.org/2026/07/28/gophermap-v0-2-0.html</link>
      <description>&lt;p&gt;A quick little update to &lt;a href="https://gophermap.davep.dev/" rel="noopener noreferrer" target="_blank"&gt;GopherMap&lt;/a&gt;.
&lt;a href="https://gophermap.davep.dev/changelog/#v020" rel="noopener noreferrer" target="_blank"&gt;v0.2.0&lt;/a&gt; greatly relaxes the
validation of incoming lines, being a lot less fussy about missing tab
characters and also about fully empty lines.&lt;/p&gt;
&lt;p&gt;In the first take on this I was being pretty strict but, unsurprisingly,
&lt;a href="https://github.com/davep/rogallo/discussions/241" rel="noopener noreferrer" target="_blank"&gt;there are sites out there with likely-malformed
maps&lt;/a&gt; that should
otherwise work if you're chill about their mistakes.&lt;/p&gt;
&lt;p&gt;I've got no desire for &lt;a href="https://blog.davep.org/tag/rogallo/"&gt;Rogallo&lt;/a&gt; to be harsh in this respect,
so here's a much more relaxed version of GopherMap.&lt;/p&gt;
&lt;p&gt;As of right now, the exceptions that are defined in the library are never
raised. I've left them in for the moment because there's a window of time
between this version being pushed to PyPI and Rogallo being updated (it does
use the exceptions), where failure to supply them would cause Rogallo to
crash under normal circumstances (nobody wants an unnecessary
&lt;code&gt;ImportError&lt;/code&gt;). Once I've updated Rogallo to pin a new lower bound, and
removed use of the exceptions, I'll remove them from GopherMap.&lt;/p&gt;</description>
      <guid isPermaLink="false">https://blog.davep.org/2026/07/28/gophermap-v0-2-0.html</guid>
      <category>Python</category>
      <category>Coding</category>
      <category>PyPI</category>
      <category>Python</category>
      <category>gopher</category>
      <category>smolweb</category>
      <pubDate>Tue, 28 Jul 2026 16:48:01 +0100</pubDate>
    </item>
  </channel>
</rss>
