<?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 Plone</title>
  <updated>2025-07-14T00:00:48.698589+00:00</updated>
  <link href="https://www.rpatterson.net/"/>
  <link href="https://www.rpatterson.net/blog/tag/plone/atom.xml" rel="self"/>
  <generator uri="https://ablog.readthedocs.io/" version="0.11.12">ABlog</generator>
  <entry>
    <id>https://www.rpatterson.net/blog/ttw-reflections-from-future/</id>
    <title>Reflections on TTW Programming from the Future</title>
    <updated>2021-04-07T00:00:00+00:00</updated>
    <author>
      <name>Ross Patterson</name>
    </author>
    <content type="html">&lt;section id="reflections-on-ttw-programming-from-the-future"&gt;

&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Playing with &lt;a class="reference external" href="https://ifttt.com/"&gt;IFTTT&lt;/a&gt; and &lt;a class="reference external" href="https://zapier.com/"&gt;Zapier&lt;/a&gt; has me remembering the TTW programming fallout
and debate.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;I’ve been working on &lt;a class="reference external" href="../feeding-ablog-to-social-media/"&gt;feeding my ABlog posts to social media&lt;/a&gt;.  I’ve been experimenting
with some external services for this, primarily because implementing something
self-hosted seems like overkill for this and it makes an excuse to explore something
I’ve been wanting to.  I’m intrigued by these services that claim to let you connect
little pieces of functionality, through an intuitive UI, to create “custom”
mini-“applications”.&lt;/p&gt;
&lt;p&gt;I’m old enough to have cut my teeth on &lt;a class="reference external" href="https://zope.org/"&gt;some of the first Through-The-Web (TTW)
programming offerings&lt;/a&gt; and thus long enough to watch the problems that became of
that. The consensus among the communities I’ve been involved in is that it’s a bad idea
to invite users and tinkerers to build their own custom applications with the promise
that it’s easier and achievable because they can do it in their browser.  The issue is
&lt;em&gt;not&lt;/em&gt; that non-programmers can’t learn to program.  They certainly can and I object to
the kind of rarefied elitism that leads others to argue otherwise.  The issue is that no
one can build the kind of custom application one can build with a full programming
language without &lt;em&gt;also&lt;/em&gt; learning most, if not all, of the suite of programming best
practices.  Without those best practices, one is all but guaranteed to end up with a
poorly engineered, unmaintainable mess.  The best case scenario is that your application
fails to become useful and thus never has a chance to become a burden.  That leaves
those who manage to create an actually useful, initially successful application that
users come to depend on.  These successful tinkerers are eventually rewarded by hitting
multiple walls at once.  Thinking about, planning for, and executing on maintainability
and other best practices are simply costs that must be paid.  The apparent savings of
not having to think about such things is an illusion and those costs have been
compounding all along behind your back.&lt;/p&gt;
&lt;p&gt;While the 10th feature was as easy to implement as the 1st, the 100th feature is 10
times as difficult as the 10th and breaks features 20-23; you can infer the curve.  You
took a stab at a major version upgrade of the framework months ago, hit another wall,
and set it aside.  Now the security/LTS of your major version is about to expire meaning
your custom application will soon be vulnerable to multiple publicly available exploits.
Change management is becoming a nightmare with duplicated code all over the place in an
effort to compensate.  A while back, you learned about VCS and the current best-of-breed
in that domain but you also realized that you couldn’t use those tools to manage your
TTW code.  There are better ways to build custom applications even within the framework
you’re using, but not TTW, the effort is comparable to re-implementing the application,
and those that can do it justly charge much more.  BTW, having learned so much from
this, you’re now worth a lot more yourself and are recruited into your first junior
programming job.  Those last two are good things, but the end result is that a team of
users is now dependent on a custom application that’s going to cost them a lot to either
replace or maintain.  They became a company in the business of developing software
without ever intending to, planning on or budgeting for.&lt;/p&gt;
&lt;p&gt;That whole process breeds resentment in a way that doesn’t come from even an equally
blundering and costly but conscious effort to develop one’s own custom software.  Like
much of human happiness, it’s expectations, the surprise, that’s the issue.  That’s how
I understand the issue with TTW programming.  If a framework provides anything
approaching a full programming language, &lt;em&gt;and&lt;/em&gt; offers or promises to save
users-come-developers some portion of software development “hassles”, then everyone is
almost certainly in for some bad-will inducing surprises.&lt;/p&gt;
&lt;p&gt;So that means that any system that allows users to assemble “applications” through a UI
meant to spare them from some portion of software development discipline needs to have
clear, rigid boundaries on expectations.  It needs to narrowly define what can be done,
place firm limits on the size of what can be built (roughly, the quantity of
components).  It doesn’t hurt to provide users an eject button so that they can export
what they’ve done to the filesystem and continue developing it incrementally using a
full software development tool chain and process.  These are the lessons the &lt;a class="reference external" href="https://plone.org/"&gt;Plone&lt;/a&gt;
community tried to learn from our &lt;a class="reference external" href="https://zope.org/"&gt;Zope&lt;/a&gt; TTW roots.  The &lt;a class="reference external" href="https://plone.org/"&gt;Plone&lt;/a&gt; community built web
UI based on these conclusions for both custom content types with custom schemata and for
custom themes.&lt;/p&gt;
&lt;p&gt;Given my involvement in that long (for software) history, I’ve been wanting to check out
&lt;a class="reference external" href="https://ifttt.com/"&gt;IFTTT&lt;/a&gt;.  Such custom applet “development” and hosting platforms are solving different
problems, very simple workflow applications connecting various internet services, but I
imagine theses same principles apply.  &lt;a class="reference external" href="https://ifttt.com/"&gt;IFTTT&lt;/a&gt; seems to employ these principles quite
firmly.  I’m not aware of any eject button that could meaningfully allow one to
incrementally build software on top of &lt;a class="reference external" href="https://ifttt.com/"&gt;IFTTT&lt;/a&gt; applets, but that wouldn’t be terribly
useful anyways given how firmly they restrict the scope of what one can do.  I don’t
have any current need for anything beyond IFTTT’s simple, two-step composition model,
the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;this&lt;/span&gt;&lt;/code&gt; component and the &lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;that&lt;/span&gt;&lt;/code&gt; component in “If this then that”, but I could
well imagine wanting more than that.  There’s also the limit on 3 applets on the free
tier of their freemium pricing plan, I am already using 2.  Finally, I couldn’t find a
&lt;code class="docutils literal notranslate"&gt;&lt;span class="pre"&gt;then&lt;/span&gt;&lt;/code&gt; component for posting to LinkedIn as a service, that’s the one that really lead
me to seek other options.&lt;/p&gt;
&lt;p&gt;I ran across &lt;a class="reference external" href="https://zapier.com/"&gt;Zapier&lt;/a&gt; a while back and was similarly intrigued, so when that showed up
in my search for something that could post to LinkedIn, I eagerly tried it out.  They
offer 5 applets, which they call “Zaps” (bit of a groaner of a term), on the free tier
of their freemium pricing plan, so point for &lt;a class="reference external" href="https://zapier.com/"&gt;Zapier&lt;/a&gt;.  I haven’t read much of their
docs, but it’s apparent in the web UI that there’s support for at least a somewhat
arbitrary chaining of more than 2 components, another win for &lt;a class="reference external" href="https://zapier.com/"&gt;Zapier&lt;/a&gt;.  I also found
their options for dealing with different “fields” in data, &lt;a class="reference external" href="https://ablog.readthedocs.io/manual/ablog-configuration-options/?highlight=feeds#blog-feeds"&gt;atom feed&lt;/a&gt; items in this
case, to be significantly more rich than those offered by &lt;a class="reference external" href="https://ifttt.com/"&gt;IFTTT&lt;/a&gt;, &lt;a class="reference external" href="https://zapier.com/"&gt;Zapier&lt;/a&gt; streaks
ahead.  They do indeed have components that interact with LinkedIn, so &lt;a class="reference external" href="https://zapier.com/"&gt;Zapier&lt;/a&gt; FTW in
this very cursory and superficial scoring.&lt;/p&gt;
&lt;p&gt;In the current moment, I’m very curious to see how the more restrictive &lt;a class="reference external" href="https://ifttt.com/"&gt;IFTTT&lt;/a&gt;
compares in the long term to the more feature-rich and composible &lt;a class="reference external" href="https://zapier.com/"&gt;Zapier&lt;/a&gt; in terms of
user experience, user maintainability, and &lt;em&gt;internal&lt;/em&gt; maintainability.  Even if I were
to pay enough attention to keep up on this, not very likely, I’m even less likely to get
access to the kind of proprietary internal discussion that could yield such insight.
C’est la capitalisme.  At any rate, It’s been fun to reflect on the issue while
automating some things.&lt;/p&gt;
&lt;/section&gt;
</content>
    <link href="https://www.rpatterson.net/blog/ttw-reflections-from-future/"/>
    <summary>Playing with IFTTT and Zapier has me remembering the TTW programming fallout
and debate.</summary>
    <category term="IFTTT" label="IFTTT"/>
    <category term="Plone" label="Plone"/>
    <category term="TTW" label="TTW"/>
    <category term="Zapier" label="Zapier"/>
    <category term="Zope" label="Zope"/>
    <published>2021-04-07T00: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/prgmr-com-vps-hosting-we-dont-assume-you-are-stupid/</id>
    <title>prgmr.com VPS: “We don’t assume you are stupid”</title>
    <updated>2013-02-04T00:00:00+00:00</updated>
    <author>
      <name>Ross Patterson</name>
    </author>
    <content type="html">&lt;section id="prgmr-com-vps-we-don-t-assume-you-are-stupid"&gt;

&lt;blockquote&gt;
&lt;div&gt;&lt;p&gt;Excellent, affordable VPS service done in a way that feels very much like participating in an open-source community.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;I just wanted to drop a quick note praising &lt;a class="reference external" href="http://prgmr.com/xen/"&gt;prgmr.com&lt;/a&gt; for their excellent and very affordable VPS service.  Unfortunately, I had to change hosting providers for other reasons but  would have been happy to stay with them indefinitely.&lt;/p&gt;
&lt;p&gt;Their slogan is “We don’t assume you are stupid” and that’s very apt.  There’s a combination of no hand-holding combined with support.  The support is a particularly good part of their service.  It’s generous but in a particular way that works very well for me.  They’ll help you up with no real hierarchy or bureaucracy up to a limit that I think almost anyone who has participated significantly in an open-source project will find familiar.  Beyond that, you’re on your own.  I really like this balance and always found the lack of bureaucracy more than worth it for any relative lack of hand-holding.&lt;/p&gt;
&lt;p&gt;At any rate, if you want an excellent and affordable VPS in the Bay Area, I can recommend no one better.&lt;/p&gt;
&lt;div class="note update admonition"&gt;
&lt;p class="admonition-title"&gt;Updated on 04 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/prgmr-com-vps-hosting-we-dont-assume-you-are-stupid/"/>
    <summary>Excellent, affordable VPS service done in a way that feels very much like participating in an open-source community.</summary>
    <category term="Plone" label="Plone"/>
    <category term="Zope" label="Zope"/>
    <published>2013-02-01T00: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>
</feed>
