<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>https://www.rpatterson.net/</id>
  <title>Ross Patterson's Blog - Posts tagged reStructuredText</title>
  <updated>2025-07-14T00:00:49.537833+00:00</updated>
  <link href="https://www.rpatterson.net/"/>
  <link href="https://www.rpatterson.net/blog/tag/restructuredtext/atom.xml" rel="self"/>
  <generator uri="https://ablog.readthedocs.io/" version="0.11.12">ABlog</generator>
  <entry>
    <id>https://www.rpatterson.net/blog/sphinx-page-dirs/</id>
    <title>Using Directories for Sphinx Pages</title>
    <updated>2021-04-05T00:00:00+00:00</updated>
    <author>
      <name>Ross Patterson</name>
    </author>
    <content type="html">&lt;section id="using-directories-for-sphinx-pages"&gt;

&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Creating &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; pages as &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./foo/index.rst&lt;/span&gt;&lt;/code&gt; has a number of benefits over
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./foo.rst&lt;/span&gt;&lt;/code&gt; including path consistency and organizing content.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;When &lt;a class="reference external" href="../migrating-from-plone-to-ablog/"&gt;I first started playing with ABlog&lt;/a&gt;, and thus learning more about Python’s
wonderful documentation tool &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt;, I observed that &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; actually creates a
directory in the built HTML output for each &lt;a class="reference external" href="https://docutils.sourceforge.io/rst.html"&gt;reStructuredText&lt;/a&gt; &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./**.rst&lt;/span&gt;&lt;/code&gt; file in the
source.  For example, if the source for this post had been
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./blog/sphinx-page-dirs.rst&lt;/span&gt;&lt;/code&gt;, &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; would render that to
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./_website/blog/sphinx-page-dirs/index.html&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One consequence of this is that a relative link to another area of the site will be
broken in the rendered HTML build output if it’s correct in the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./**.rst&lt;/span&gt;&lt;/code&gt; source
file.  For example, if &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./about.rst&lt;/span&gt;&lt;/code&gt; contains a link such as:&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;See &lt;span class="s"&gt;`the blog area to see all posts &lt;/span&gt;&lt;span class="si"&gt;&amp;lt;./blog/&amp;gt;&lt;/span&gt;&lt;span class="s"&gt;`_&lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; HTML build output will render that &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./about.rst&lt;/span&gt;&lt;/code&gt; file to
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./about/index.html&lt;/span&gt;&lt;/code&gt; and thus the link will point to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;/about/blog/&lt;/span&gt;&lt;/code&gt; instead of the
intended &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;/blog/&lt;/span&gt;&lt;/code&gt;.  I dimly recall encountering such path issues with other types of
reST path references as well.  Path consistency is also particularly handy for editors
or other tools that can infer enough to open files from path references in other files,
such as &lt;a class="reference external" href="https://www.gnu.org/software/emacs/manual/html_node/emacs/FFAP.html"&gt;FFAP&lt;/a&gt; in &lt;a class="reference external" href="https://www.gnu.org/software/emacs/"&gt;Emacs&lt;/a&gt;.  Writing the source reST for a page as
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./about/index.rst&lt;/span&gt;&lt;/code&gt; in the first place nicely avoids those problems and empowers such
tools.&lt;/p&gt;
&lt;p&gt;I’m not a big fan of embedding code of one sort into content (or code) of another sort.
For example, as big an &lt;a class="reference external" href="https://orgmode.org/"&gt;Org-mode&lt;/a&gt; fan as I am, I’ve never been able to get into using
&lt;a class="reference external" href="https://orgmode.org/worg/org-contrib/babel/"&gt;Babel&lt;/a&gt;.  In this case, when writing documentation or other text content, I resist
embedding code into source text files and prefer to have such code in separate files
next to the text.  If the code I want to include in documentation is actual used code,
as was the case with &lt;a class="reference external" href="../migrating-from-plone-to-ablog/"&gt;the export/import scripts that migrated this blog&lt;/a&gt;, then it saves
time copying and pasting and prevents out-of-date content when forgetting to do so.
Even if it is example or demonstration code of more than a few lines, having it in
separate sibling files supports using all our favorite tools (static analysis, IDEs,
editors, etc.) which further prevents incorrect or misleading examples.  So instead of
&lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#literal-blocks"&gt;reStructuredText’s :: literal blocks&lt;/a&gt; or Markdown’s indented code blocks I’d much
rather include code from separate files.  Using a directory for such pages,
e.g. &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;./blog/migrating-from-plone-to-ablog/&lt;/span&gt;&lt;/code&gt;, also allows us to keep such related
files organized neatly together.&lt;/p&gt;
&lt;p&gt;Finally, using a directory for a &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; page supports putting all related content
into a separate VCS repository checkout, such as via &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;$&lt;/span&gt; &lt;span class="pre"&gt;git&lt;/span&gt; &lt;span class="pre"&gt;submodule&lt;/span&gt; &lt;span class="pre"&gt;...&lt;/span&gt;&lt;/code&gt;.  This can
be very useful for sharing code related to one page without having to share the source
and VCS history for the whole site.  For example, I have an upcoming post with a
non-trivial amount of working and tested demo code I want to share.  I can use this
approach to make that code and VCS history public while still preserving the option of
having private content or VCS history for the rest of this site.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://www.rpatterson.net/blog/sphinx-page-dirs/"/>
    <summary>Creating Sphinx pages as ./foo/index.rst has a number of benefits over
./foo.rst including path consistency and organizing content.</summary>
    <category term="ABlog" label="ABlog"/>
    <category term="Python" label="Python"/>
    <category term="Sphinx" label="Sphinx"/>
    <category term="reStructuredText" label="reStructuredText"/>
    <published>2021-04-05T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://www.rpatterson.net/blog/migrating-from-plone-to-ablog/</id>
    <title>Migrating From Plone To ABlog</title>
    <updated>2021-03-16T00:00:00+00:00</updated>
    <author>
      <name>Ross Patterson</name>
    </author>
    <content type="html">&lt;section id="migrating-from-plone-to-ablog"&gt;

&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;My aspiration to return to blogging thanks to &lt;a class="reference external" href="https://docutils.sourceforge.io/rst.html"&gt;reStructuredText&lt;/a&gt;, &lt;a class="reference external" href="https://ablog.readthedocs.io/"&gt;ABlog&lt;/a&gt; and
&lt;a class="reference external" href="https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_from_scratch.html"&gt;GitLab CI/CD&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;I stopped blogging years ago.  I was never very good at blogging regularly, I always
seem to prefer adding further polish to whatever I’m working on over sharing what I’ve
learned.  But it didn’t help that my old blogging platform, self-hosted &lt;a class="reference external" href="http://plone.org"&gt;Plone&lt;/a&gt;, was
too heavy for the job.  The maintenance work kept piling up and every time I thought of
blogging, I’d remember that &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;TODO&lt;/span&gt;&lt;/code&gt; list and then do something else instead.  :-/&lt;/p&gt;
&lt;p&gt;I want to be very clear.  &lt;a class="reference external" href="http://plone.org"&gt;Plone&lt;/a&gt;, the open-source enterprise CMS, is a simply awesome
piece of software and a remarkable open-source project.  The list of features provided
is both extensive and powerful and the capacity to extend those features and frameworks
to build custom CMS’ish applications is even more powerful.  Finally and foremost, being
involved in the open-source community that develops and maintains that software
ecosystem has been the most rewarding part of my career in software.  Lovely people.&lt;/p&gt;
&lt;p&gt;Plone is, however, laughably overkill for a software developer’s professional blog.  My
intention was &lt;a class="reference external" href="../../news/about-this-site/"&gt;to eat my own dog-food&lt;/a&gt; by using the CMS that I spent most of my time
working with at the time.  That intention is perfectly reasonable but my work stream has
mostly moved away from Plone in the intervening years and the maintenance burden is
never small for such a large feature set, even if you’re using almost none of those
features.  I’ll try to learn the lesson here to moderate the impulse to dog-food.&lt;/p&gt;
&lt;p&gt;Blogging is writing.  Text (as opposed to a WYSIWYG word processor, for example) is the
format for writing that least gets in the way when one is proficient with a programmer’s
editor.  Python’s magnificent &lt;a class="reference external" href="https://docutils.sourceforge.io/rst.html"&gt;reStructuredText&lt;/a&gt; is the most expressive text markup
language out there and provides a number of features that one inevitably needs when
doing much more than writing a heading, 3 paragraphs, 2 lists and 5 links.  &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt; is
the lingua franca for writing documentation in the &lt;a class="reference external" href="http://www.python.org/"&gt;Python&lt;/a&gt; world and beyond, and for
very good reason.&lt;/p&gt;
&lt;p&gt;I’ve known for some time, given the above, that I wanted to blog in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;reST&lt;/span&gt;&lt;/code&gt; and I also
want to become more familiar with Sphinx, so I went looking for static site generators
based on Sphinx.  I evaluated &lt;a class="reference external" href="https://ablog.readthedocs.io/"&gt;ABlog&lt;/a&gt; and &lt;a class="reference external" href="http://tinkerer.me/index.html"&gt;Tinkerer&lt;/a&gt;, both blogging-oriented static
site generators based on Sphinx.  I like that &lt;a class="reference external" href="https://ablog.readthedocs.io/"&gt;ABlog&lt;/a&gt; seems to be a little less
opinionated and calls itself a Sphinx extension since I may well want to use this
platform for static site content beyond just blogging.  It also seems like &lt;a class="reference external" href="https://ablog.readthedocs.io/"&gt;ABlog&lt;/a&gt; is
actively maintained while the last release of &lt;a class="reference external" href="http://tinkerer.me/index.html"&gt;Tinkerer&lt;/a&gt; was in 2017.  Given what I
read in a few other reviews and comments I made the call to go with &lt;a class="reference external" href="https://ablog.readthedocs.io/"&gt;Ablog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next up I needed to decide whether to preserve my Plone blogging content or start
afresh.  Given that I’m bad at getting around to blogging, I thought exporting my old
posts would help fill things out a but, though one glance at the dates gives that game
away.  ;-)  It also seemed like a fun problem to solve.&lt;/p&gt;
&lt;p&gt;Given that the target is text files and a static site generator, I decided to write
&lt;a class="reference download internal" download="" href="../../../_downloads/27af34257a1b36c7a97f3a7c4b1d52f7/export_content.py"&gt;&lt;code class="xref download docutils literal notranslate"&gt;&lt;span class="pre"&gt;the&lt;/span&gt; &lt;span class="pre"&gt;export&lt;/span&gt; &lt;span class="pre"&gt;script&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; oriented towards files on
the filesystem and as agnostic about the internals of Plone as possible.  I’m pretty
happy with it for such a pragmatic bit of “software” and I think it does a surprisingly
decent job of capturing as much as possible the data and metadata of Plone content in a
format most appropriate for files in a filesystem and oriented to file and text-oriented
tools.  In particular, it exports text fields the format of the “native” MIME type of
that field instance, mostly so that posts I wrote in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;reST&lt;/span&gt;&lt;/code&gt; would remain in that
format on export.  It will also export multiple, separate file-like fields to separate
files preserving any per-field filename if available.  For example, the lead images for
Plone &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;News&lt;/span&gt; &lt;span class="pre"&gt;Item&lt;/span&gt;&lt;/code&gt; instances, were written next to the corresponding &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;reST&lt;/span&gt;&lt;/code&gt; file with
the original uploaded image &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;basename&lt;/span&gt;&lt;/code&gt;.  Finally, it also uses the FTP/WebDAV support
built into Zope to export most, if not all, other fields to a corresponding
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.properties&lt;/span&gt;&lt;/code&gt; file in RFC822 format.&lt;/p&gt;
&lt;p&gt;Now that I had files reflecting the Plone representation of the content, I created a new
repository, copied the files there and began working on massaging them into &lt;a class="reference external" href="https://ablog.readthedocs.io/"&gt;ABlog&lt;/a&gt;
posts.  I learned about &lt;a class="reference external" href="https://docutils.sourceforge.io/docs/ref/rst/directives.html#raw-data-pass-through"&gt;the reST ‘.. raw:: html’ directive&lt;/a&gt; for the Plone content I
wrote using the WYSIWYG editor and was thus in HTML format in the exported files.  It
works nicely and some quick shell commands created an &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.rst&lt;/span&gt;&lt;/code&gt; file corresponding to
each &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.html&lt;/span&gt;&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; html
   &lt;span class="nc"&gt;:file:&lt;/span&gt; ./{id}.html
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Thus having &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.rst&lt;/span&gt;&lt;/code&gt; files for each exported post, it was time to convert them into
ABlog posts.  I wanted to preserve all metadata from the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;*.properties&lt;/span&gt;&lt;/code&gt; files that
corresponded to &lt;a class="reference external" href="https://ablog.readthedocs.io/manual/posting-and-listing/#directive-post"&gt;ABlog post metadata&lt;/a&gt; or could reasonably be added to the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;reST&lt;/span&gt;&lt;/code&gt;
surrounding the main content of the post.  Again, I’m pretty happy with how much
&lt;a class="reference download internal" download="" href="../../../_downloads/36e9f66a595dfeedf8871d39979a3b9a/rfc822-to-post"&gt;&lt;code class="xref download docutils literal notranslate"&gt;&lt;span class="pre"&gt;the&lt;/span&gt; &lt;span class="pre"&gt;import&lt;/span&gt; &lt;span class="pre"&gt;script&lt;/span&gt;&lt;/code&gt;&lt;/a&gt; was able to preserve.  I
don’t think I’ll miss any of the excluded metadata:&lt;/p&gt;
&lt;div class="highlight-rst notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gh"&gt;#######&lt;/span&gt;
&lt;span class="gh"&gt;{title}&lt;/span&gt;
&lt;span class="gh"&gt;#######&lt;/span&gt;

    {description}

&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; html
   &lt;span class="nc"&gt;:file:&lt;/span&gt; ./{id}.html


&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;
   &lt;span class="nc"&gt;:description:&lt;/span&gt; {description}
   &lt;span class="nc"&gt;:keywords:&lt;/span&gt; {subject}

&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;post&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; {creation_date}
   &lt;span class="nc"&gt;:tags:&lt;/span&gt; {subject}
   &lt;span class="nc"&gt;:author:&lt;/span&gt; Ross Patterson
   &lt;span class="nc"&gt;:redirect:&lt;/span&gt;  @@redirect-to-uuid/{UID}

&lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="ow"&gt;update&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt; {modification_date}

   Imported from Plone on {now}.  The date for this update is the last
   modified date in Plone.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If any of the above export/import code would be useful to anyone else, LMK and I’ll
throw it up to a separate GitLab repository under an open-source license along with my
VCS history.&lt;/p&gt;
&lt;p&gt;With all the content showing up nicely in the output from the &lt;a class="reference external" href="https://ablog.readthedocs.io/manual/watch-yourself-blogging/"&gt;ABlog watchdog,
auto-rebuild development server&lt;/a&gt;, I fixed a few formatting issues in the imported
content, updated the boilerplate content, and went looking for a theme.  I do prefer
dark themes but mostly, much to my chagrin, I’ve noticed that many if not most people
seem to think less of you if you show them something with the default theme, even when
the person showing you is decidedly &lt;em&gt;not&lt;/em&gt; a designer.  ;-) I found &lt;a class="reference external" href="https://git.sr.ht/~sporiff/alabaster-solarised"&gt;a dark Solarized
theme that extends the default theme&lt;/a&gt; and &lt;a class="reference external" href="https://git.sr.ht/~rpatterson/alabaster-solarised/commit/3ea216cecf5756ca631935ba2d3a33d176806d4d"&gt;contributed some fixes&lt;/a&gt;.  It’s certainly
not perfect, but I like it better than the default and it certainly expresses that this
is the blog of a developer.&lt;/p&gt;
&lt;p&gt;Finally, I created a private GitLab repository and whipped up a simple &lt;a class="reference external" href="https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_from_scratch.html"&gt;GitLab CI/CD&lt;/a&gt;
configuration that builds and deploys the built static site to GitLab Pages when I push
to master.  I added some &lt;a class="reference external" href="https://docs.gitlab.com/13.9/ee/user/project/pages/redirects.html"&gt;GitLab redirects&lt;/a&gt; for the few paths that changed.  BTW, this
is one of the nice things about &lt;a class="reference external" href="https://ablog.readthedocs.io/"&gt;ABlog&lt;/a&gt; so far, most paths stayed the same.  I pushed
to &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;master&lt;/span&gt;&lt;/code&gt; and viola!&lt;/p&gt;
&lt;p&gt;Do LMK if you find any bugs.  This ended up being more complete than I would have
expected so I’d love to know of any issues I missed.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://www.rpatterson.net/blog/migrating-from-plone-to-ablog/"/>
    <summary>My aspiration to return to blogging thanks to reStructuredText, ABlog and
GitLab CI/CD.</summary>
    <category term="ABlog" label="ABlog"/>
    <category term="Plone" label="Plone"/>
    <category term="Python" label="Python"/>
    <category term="Sphinx" label="Sphinx"/>
    <category term="reStructuredText" label="reStructuredText"/>
    <published>2021-03-16T00:00:00+00:00</published>
  </entry>
</feed>
