<?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 Python</title>
  <updated>2025-07-14T00:00:48.803731+00:00</updated>
  <link href="https://www.rpatterson.net/"/>
  <link href="https://www.rpatterson.net/blog/tag/python/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>
  <entry>
    <id>https://www.rpatterson.net/blog/emerald-sprint-report-out/</id>
    <title>Emerald Sprint Report Out</title>
    <updated>2013-02-13T00:00:00+00:00</updated>
    <author>
      <name>Ross Patterson</name>
    </author>
    <content type="html">&lt;section id="emerald-sprint-report-out"&gt;

&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Merging versioning and and constrained types into Dexterity near Beautiful Seattle.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Thanks to the fabulous &lt;a class="reference external" href="http://seattleplone.org"&gt;Seattle Plone folk&lt;/a&gt;, we had another west
coast sprint, the &lt;a class="reference external" href="http://www.coactivate.org/projects/emerald-sprint/project-home"&gt;Emerald Sprint&lt;/a&gt;, on lovely &lt;a class="reference external" href="https://maps.google.com/maps?q=48.16269,-122.467258&amp;amp;ll=47.890564,-122.437134&amp;amp;spn=2.232193,5.410767&amp;amp;num=1&amp;amp;t=h&amp;amp;gl=us&amp;amp;z=8"&gt;Camano Island&lt;/a&gt;.  The
focus was polishing &lt;a class="reference external" href="http://pypi.python.org/pypi/plone.app.dexterity"&gt;Dexterity&lt;/a&gt;, it was a gorgeous location, a very
productive sprint, and I very much hope we can make it an annual
thing.  We might have a better chance at that if we choose a topic
next year such that &lt;a class="reference external" href="http://glicksoftware.com/"&gt;David&lt;/a&gt; can just be another sprinter for once.
:-)&lt;/p&gt;
&lt;p&gt;Firstly, I have to give a huge shout out to our Maven of Fine Dining,
&lt;a class="reference external" href="http://www.linkedin.com/in/skleinfeldt"&gt;Sally&lt;/a&gt;, and to &lt;a class="reference external" href="www.linkedin.com/pub/alice-tseng/4/275/530"&gt;Alice&lt;/a&gt; for yet more above-and-beyond contributions
to the culinary experience of this sprint.  The food was simply
incredible and I have to say I &lt;em&gt;love&lt;/em&gt; a sprint that has that element.
I was spoiled before by the cooking at the &lt;a class="reference external" href="../cioppino-sprint-2012"&gt;Cioppino Sprint&lt;/a&gt; and the
&lt;a class="reference external" href="../sea-sprint-2012-report-out"&gt;Sea Sprint&lt;/a&gt; and the food at this sprint may have out done them!&lt;/p&gt;
&lt;p&gt;The sprint location was an excellent choice and everything was very
well organized by &lt;a class="reference external" href="http://crisewing.com/"&gt;Cris&lt;/a&gt;, &lt;a class="reference external" href="https://twitter.com/luke_brannon"&gt;Luke&lt;/a&gt;, &lt;a class="reference external" href="http://solitonconsulting.com/"&gt;Fulvio&lt;/a&gt; and &lt;a class="reference external" href="http://glicksoftware.com/"&gt;David&lt;/a&gt;.  I was
very sad to learn that &lt;a class="reference external" href="http://crisewing.com/"&gt;Cris&lt;/a&gt; wasn’t going to be able to stay for the
sprint and wish him the best.  Thanks also to &lt;a class="reference external" href="http://andersonleeb.com/"&gt;Ian Anderson and Andy
Leeb&lt;/a&gt; for treating us to a delicious dinner out on our first night.&lt;/p&gt;
&lt;p&gt;We did a brainstorming session where we all voted for what we found to
be the most important.  Then &lt;a class="reference external" href="http://glicksoftware.com/"&gt;David&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/MatthewWilkes"&gt;Matthew&lt;/a&gt; marked the items
that they thought were clear low-hanging fruit that didn’t require a
lot of design or other discussion. After seeing what the other
sprinters chose for I opted for tackling some of the remaining
low-hanging fruit.  That ended up being two tasks both of which
involved merging work done by others previously in add-ons or other
packages not in Dexterity core where they belong: &lt;a class="reference external" href="https://trello.com/card/better-versioning-support/50d18b10540c21f830003269/9"&gt;versioning&lt;/a&gt; and
&lt;a class="reference external" href="https://trello.com/card/ui-for-setting-the-subtypes-for-containers/50d18b10540c21f830003269/21"&gt;constrained types&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Working on &lt;a class="reference external" href="https://trello.com/card/better-versioning-support/50d18b10540c21f830003269/9"&gt;versioning&lt;/a&gt; involved merging two add-on packages into
&lt;a class="reference external" href="http://pypi.python.org/pypi/plone.app.dexterity"&gt;Dexterity&lt;/a&gt; core.  The &lt;a class="reference external" href="http://pypi.python.org/pypi/collective.cmfeditionsdexteritycompat"&gt;collective.cmfeditionsdexteritycompat&lt;/a&gt;
add-on makes it possible to use the history view on Dexterity content
and I merged it into &lt;a class="reference external" href="http://pypi.python.org/pypi/plone.app.versioningbehavior"&gt;plone.app.versioningbehavior&lt;/a&gt;.  The
&lt;a class="reference external" href="http://pypi.python.org/pypi/collective.dexteritydiff"&gt;collective.dexteritydiff&lt;/a&gt; add-on brings parity with &lt;a class="reference external" href="http://plone.org/products/archetypes"&gt;Archetypes&lt;/a&gt;
when viewing diffs between versions and I merged it into
&lt;a class="reference external" href="http://pypi.python.org/pypi/Products.CMFDiffTool"&gt;Products.CMFDiffTool&lt;/a&gt;.  Both packages were done by &lt;a class="reference external" href="http://rafaelb.objectis.net/"&gt;Rafael
Oliveira&lt;/a&gt; and worked perfectly, my only job was doing the merge and
reconciling the tests.  Fortunately, &lt;a class="reference external" href="http://rafaelb.objectis.net/"&gt;Rafael&lt;/a&gt; had written tests &lt;em&gt;and&lt;/em&gt;
had done so using &lt;a class="reference external" href="http://pypi.python.org/pypi/plone.app.testing/4.2.2"&gt;plone.app.testing&lt;/a&gt;.  &lt;em&gt;Unfortunately&lt;/em&gt;,
&lt;a class="reference external" href="http://pypi.python.org/pypi/Products.CMFEditions"&gt;Products.CMFEditions&lt;/a&gt; does not use &lt;a class="reference external" href="http://pypi.python.org/pypi/plone.app.testing/4.2.2"&gt;plone.app.testing&lt;/a&gt; and since
such tests can not run in the same test run as &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ZopeTestCase&lt;/span&gt;&lt;/code&gt; tests
are run, that meant I had to back-port the tests &lt;a class="reference external" href="http://rafaelb.objectis.net/"&gt;Rafael&lt;/a&gt; wrote off
of &lt;a class="reference external" href="http://pypi.python.org/pypi/plone.app.testing/4.2.2"&gt;plone.app.testing&lt;/a&gt; back to &lt;cite&gt;ZopeTestCase&lt;/cite&gt;.  I hate going
backwards but enough things build on the &lt;a class="reference external" href="http://pypi.python.org/pypi/Products.CMFEditions"&gt;Products.CMFEditions&lt;/a&gt; tests
that I guessed it would take too long and be to disruptive to convert
all those tests.  After that, I spent the rest of the sprint trying to
complete my &lt;a class="reference external" href="https://github.com/plone/plone.app.testing/tree/simpler-helpers"&gt;plone.app.testing.api&lt;/a&gt; branch which is intended to make
such conversions easier.&lt;/p&gt;
&lt;p&gt;I also had the opportunity to bring &lt;a class="reference external" href="https://picasaweb.google.com/lh/photo/Pq5EEJ3K2izy6gP4aGsrJNMTjNZETYmyPJy0liipFm0?feat=directlink"&gt;Gin Apocrypha&lt;/a&gt; with me and bar
tend for the event.  It was my first time trying to check enough items
on the plane to be able to mix my whole menu and it actually worked
out very well.  So I think I may be willing to check a bag in the
future to be able to bring &lt;a class="reference external" href="https://picasaweb.google.com/lh/photo/Pq5EEJ3K2izy6gP4aGsrJNMTjNZETYmyPJy0liipFm0?feat=directlink"&gt;Gin Apocrypha&lt;/a&gt; to events I don’t drive to
in the future!&lt;/p&gt;
&lt;p&gt;It was a great sprint and I love the Seattle area so I really hope
this happens again.  This sprint being focused on &lt;a class="reference external" href="http://pypi.python.org/pypi/plone.app.dexterity"&gt;Dexterity&lt;/a&gt; and
&lt;a class="reference external" href="http://glicksoftware.com/"&gt;David&lt;/a&gt; being Dexterity’s maintainer and fearless leader, I know I
pestered him a lot as I needed to ask questions and get perspective,
but he did a great job facilitating everything.  For that reason if no
other, I hope the next Emerald Sprint can be on a topic such that
David can get back to basics and enjoy being just another sprinter
again.  :-)&lt;/p&gt;
&lt;div class="note update admonition"&gt;
&lt;p class="admonition-title"&gt;Updated on 13 February 2013&lt;/p&gt;
&lt;p&gt;Imported from Plone on Mar 15, 2021.  The date for this update is the last
modified date in Plone.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
</content>
    <link href="https://www.rpatterson.net/blog/emerald-sprint-report-out/"/>
    <summary>Merging versioning and and constrained types into Dexterity near Beautiful Seattle.</summary>
    <category term="Plone" label="Plone"/>
    <category term="Python" label="Python"/>
    <category term="Testing" label="Testing"/>
    <category term="Zope" label="Zope"/>
    <published>2013-02-13T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://www.rpatterson.net/blog/poskeyerror-during-commit/</id>
    <title>POSKeyError During Commit</title>
    <updated>2012-11-21T00:00:00+00:00</updated>
    <author>
      <name>Ross Patterson</name>
    </author>
    <content type="html">&lt;section id="poskeyerror-during-commit"&gt;

&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;A terrifying tale of ZODB errors that only showed during the hardest time to debug.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Believe it or not, I’m a &lt;a class="reference external" href="http://plonechix.blogspot.com/2009/12/definitive-guide-to-poskeyerror.html"&gt;POSKeyError&lt;/a&gt; virgin, I’ve never run into
one…  Until now!&lt;/p&gt;
&lt;p&gt;I was working on a very small &lt;a class="reference external" href="http://plone.org"&gt;Plone&lt;/a&gt; 3.1.1 to 4.2.2 upgrade.  Not too
many add-ons, simple skin/theme customizations, 1,810 objects in
~800MB.  No problem, right?&lt;/p&gt;
&lt;p&gt;Wrong.  I got a &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;POSKeyError&lt;/span&gt;&lt;/code&gt; after the upgrade step that converts
files and images to &lt;a class="reference external" href="http://svn.zope.org/ZODB/trunk/src/ZODB/blob.py?view=markup"&gt;BLOBs&lt;/a&gt;.  The wierd part is that it only happened
during the &lt;a class="reference external" href="http://www.zodb.org/zodbbook/transactions.html"&gt;transaction.commit()&lt;/a&gt;, not during &lt;a class="reference external" href="http://zodb.org"&gt;ZODB&lt;/a&gt; object access:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/Zope2-2.13.18-py2.7.egg/Zope2/App/startup.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;
    &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/transaction-1.1.1-py2.7.egg/transaction/_manager.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/transaction-1.1.1-py2.7.egg/transaction/_transaction.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;329&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_commitResources&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/transaction-1.1.1-py2.7.egg/transaction/_transaction.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_commitResources&lt;/span&gt;
    &lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/ZODB3-3.10.5-py2.7-linux-x86_64.egg/ZODB/Connection.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;572&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;
    &lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/ZODB3-3.10.5-py2.7-linux-x86_64.egg/ZODB/BaseStorage.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;416&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;checkCurrentSerialInTransaction&lt;/span&gt;
    &lt;span class="n"&gt;committed_tid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/ZODB3-3.10.5-py2.7-linux-x86_64.egg/ZODB/FileStorage/FileStorage.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;770&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;getTid&lt;/span&gt;
    &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lookup_pos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/opt/src/eggs/ZODB3-3.10.5-py2.7-linux-x86_64.egg/ZODB/FileStorage/FileStorage.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_lookup_pos&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;POSKeyError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;POSKeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;0x055350&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I tried all the tools in &lt;a class="reference external" href="http://svn.zope.org/ZODB/trunk/src/ZODB/scripts/README.txt?view=markup"&gt;ZODB.scripts&lt;/a&gt; and &lt;cite&gt;zc.zodbdgc&lt;/cite&gt; but they
couldn’t tell me anything about the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;oid&lt;/span&gt;&lt;/code&gt; in question.  That’s
probably because it was a different &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;oid&lt;/span&gt;&lt;/code&gt; every time I attempted the
upgrade step &lt;em&gt;on the same ZODB&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Without being able to use the typical tools to find out what ZODB
objects were referring to those &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;oids&lt;/span&gt;&lt;/code&gt; I was really stuck.  Then &lt;a class="reference external" href="http://glicksoftware.com/"&gt;David
Glick&lt;/a&gt; came to my rescue.  Actually, he was staying at my apartment
so I drafted him.  :-)  He suggested that I might have to create a
mapping of &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;oids&lt;/span&gt;&lt;/code&gt; to stack frames at the time when objects were added
to the transaction so that I could figure out what &lt;em&gt;had been&lt;/em&gt; going on
once I knew &lt;em&gt;which&lt;/em&gt; &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;oid&lt;/span&gt;&lt;/code&gt; would be the problem.  This worked very well
and much thanks to David.&lt;/p&gt;
&lt;p&gt;I added the following to the place where the objects were being added
to the transaction, &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;ZODB.Connection.Connection.readCurrent()&lt;/span&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;XXX&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_p_oid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_getframe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then once I had my &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;POSKeyError&lt;/span&gt;&lt;/code&gt; in &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pdb.post_mortem()&lt;/span&gt;&lt;/code&gt; I could invoke
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;pdb&lt;/span&gt;&lt;/code&gt; at the place where the offending &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;oid&lt;/span&gt;&lt;/code&gt; had been added:&lt;/p&gt;
&lt;div class="highlight-default notranslate"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pdb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pdbr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pdb&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pdbr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pdbr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Using that I was able to find out what objects were involved.  They
were all &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;portal_catalog/path&lt;/span&gt;&lt;/code&gt; index &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;Trees.IIBTree.IITreeSet&lt;/span&gt;&lt;/code&gt;
objects.  What’s odd is that the error happens even if I do a catalog
clear and rebuild first.&lt;/p&gt;
&lt;p&gt;After much more debugging and discussion, we determined that the
&lt;a class="reference external" href="http://zope3.pov.lt/trac/browser/ZODB/trunk/src/ZODB/interfaces.py#L289"&gt;ZODB.Connection.Connection.readCurrent()&lt;/a&gt; support was involved
somehow.  Also, as I deleted the images that were involved I noticed
another migration error earlier on went away for each image I
removed.  That’s the key, when the BLOB migration fails for one file
or image, it uses a savepoint to rollback &lt;em&gt;just&lt;/em&gt; that image’s
migration and proceed with the rest.  It sure seems like there’s a bug
in the ZODB where when a savepoint is rolled back the objects
registered with the transaction are cleaned up but the objects
registered for &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;readCurrent&lt;/span&gt;&lt;/code&gt; are not.  Gee, someone should write a
test case.  :-)&lt;/p&gt;
&lt;p&gt;In the meantime, it turns out the &lt;a class="reference external" href="https://github.com/plone/plone.app.blob/commit/d06895d4a026539e5eb8717e7df9832104bf350c"&gt;reason the image migrations were
failing&lt;/a&gt; was something else all together but I thought I should share
this debugging technique for capturing stack information when you
can’t know which stack you need to inspect until later.  I also hope
this ZODB bug gets squashed.&lt;/p&gt;
&lt;div class="note update admonition"&gt;
&lt;p class="admonition-title"&gt;Updated on 21 November 2012&lt;/p&gt;
&lt;p&gt;Imported from Plone on Mar 15, 2021.  The date for this update is the last
modified date in Plone.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
</content>
    <link href="https://www.rpatterson.net/blog/poskeyerror-during-commit/"/>
    <summary>A terrifying tale of ZODB errors that only showed during the hardest time to debug.</summary>
    <category term="Plone" label="Plone"/>
    <category term="Python" label="Python"/>
    <category term="Zope" label="Zope"/>
    <published>2012-11-21T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://www.rpatterson.net/blog/wsgi-apps-on-iis/</id>
    <title>WSGI apps on IIS</title>
    <updated>2012-10-30T00:00:00+00:00</updated>
    <author>
      <name>Ross Patterson</name>
    </author>
    <content type="html">&lt;section id="wsgi-apps-on-iis"&gt;

&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;iiswsgi provides a WSGI server providing a FCGI gateway to IIS and setup.py commands for distributing apps as WebPI packages&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://github.com/rpatterson/iiswsgi"&gt;iiswsgi&lt;/a&gt; module implements a FastCGI to &lt;a class="reference external" href="http://wsgi.readthedocs.org/en/latest/"&gt;WSGI&lt;/a&gt; gateway that
is compatible with &lt;a class="reference external" href="http://www.iis.net"&gt;IIS&lt;/a&gt;’s variation of the &lt;a class="reference external" href="http://www.fastcgi.com/drupal/"&gt;FastCGI protocol&lt;/a&gt;.  It also
provides &lt;a class="reference external" href="http://docs.python.org/distutils/"&gt;distutils&lt;/a&gt; commands for building, distributing and installing
&lt;a class="reference external" href="http://www.iis.net/downloads/microsoft/web-deploy"&gt;Microsoft Web Deploy&lt;/a&gt; (MSDeploy) packages through the &lt;a class="reference external" href="http://www.microsoft.com/web/downloads/platform.aspx"&gt;Web Platform
Installer&lt;/a&gt; (WebPI).&lt;/p&gt;
&lt;p&gt;The goals of the code in &lt;a class="reference external" href="https://github.com/rpatterson/iiswsgi"&gt;iiswsgi&lt;/a&gt; are to do the following for
deploying WSGI apps on IIS:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;make it open source as far as possible, right up to IIS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;be Pythonic as far as possible, right up to the MSDeploy packaging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;re-use our existing tool-chain for distributing packages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;share the maintenance burden for a WSGI on Windows story across the community&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the &lt;a class="reference external" href="http://plone.org"&gt;Plone&lt;/a&gt; project, it’s always been simultaneously a necessity
that we support a Windows deployment story and one of our biggest pain
points.  The Windows installers have always been very different from
the other installers.  They have had different layouts from our user
and developer documentation and even from each other.  They have never
been maintained or supported by more than one entity, either a company
or an individual, and as such have often and ultimately languished.
And as for the poor individuals who have tackled the Windows
installers, they have almost always burned out and can no longer
provide any significant Windows support at all.  This is not a healthy
open source community dynamic.  And yet there is wide consensus that
it’s not an option &lt;em&gt;not&lt;/em&gt; to have a Windows deployment story.&lt;/p&gt;
&lt;p&gt;My hope is that by generalizing the IIS deployment architecture as a
&lt;a class="reference external" href="https://github.com/rpatterson/iiswsgi#iiswsgi-fcgi-gateway"&gt;WSGI server&lt;/a&gt; and &lt;a class="reference external" href="https://github.com/rpatterson/iiswsgi#build-msdeploy-package"&gt;distutils commands&lt;/a&gt;, it can be of use to the
general Python &lt;a class="reference external" href="http://wsgi.readthedocs.org/en/latest/"&gt;WSGI&lt;/a&gt; world.  I also hope that by doing things ‘The
Right Way’, it will be something that will be clearer and easy to
support and maintain.  With those two together maybe we can solve the
burnout issue by distributing the maintenance load.  I’d very much
appreciate any help to that end, particularly including feedback on
how to get there.  I don’t care where the code lives and would be
happy to see some of it merged back into the packages it derives from
or moved into larger packages.  So please let me know if you’d like to
coordinate moving things around with me.&lt;/p&gt;
&lt;section id="help-needed"&gt;
&lt;h2&gt;Help Needed&lt;/h2&gt;
&lt;p&gt;Any contributions are very welcome.  Here are a few things I’m looking
for in particular:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;addressing &lt;a class="reference external" href="https://github.com/rpatterson/iiswsgi#known-issues"&gt;Known Issues&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IIS app name and Python dist name conventions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fostering community ownership&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;writing tests&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m particularly apologetic for the last one, I’m ashamed by the lack
of tests.  In my defense, this whole problem was such a fog for me
when I started that I just needed to start writing things and poking
around.  Believe me this is not my usual MO, I almost always do TDD
and beg your forgiveness.  :-)&lt;/p&gt;
&lt;p&gt;I look forward to getting this going!&lt;/p&gt;
&lt;div class="note update admonition"&gt;
&lt;p class="admonition-title"&gt;Updated on 30 October 2012&lt;/p&gt;
&lt;p&gt;Imported from Plone on Mar 15, 2021.  The date for this update is the last
modified date in Plone.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
</content>
    <link href="https://www.rpatterson.net/blog/wsgi-apps-on-iis/"/>
    <summary>iiswsgi provides a WSGI server providing a FCGI gateway to IIS and setup.py commands for distributing apps as WebPI packages</summary>
    <category term="Plone" label="Plone"/>
    <category term="Python" label="Python"/>
    <category term="Zope" label="Zope"/>
    <category term="fastcgi" label="fastcgi"/>
    <category term="fcgi" label="fcgi"/>
    <category term="iis" label="iis"/>
    <category term="msdeploy" label="msdeploy"/>
    <category term="webpi" label="webpi"/>
    <category term="wsgi" label="wsgi"/>
    <published>2012-10-30T00:00:00+00:00</published>
  </entry>
</feed>
