For a customer I need to do lot's of checks on the live site. Because of reasons(TM) I have a browser view as a test runner, which then runs several of the tests. The tests ran fine indiviually, but when running some of them in the same request, I got the following issues error message:
2015-06-02 16:21:27 ERROR Zope.SiteErrorLog 1433254887.110.276035955441 http://localhost/p8/batests Traceback (innermost last): Module plone.app.portlets.manager, line 63, in safe_render Module plone.memoize.volatile, line 276, in replacement Module plone.app.portlets.portlets.recent, line 40, in _render_cachekey Module plone.app.portlets.cache, line 29, in render_cachekey Module plone.app.portlets.cache, line 27, in add Module Products.ZCatalog.CatalogBrains, line 51, in getPath Module Products.ZCatalog.ZCatalog, line 518, in getpath KeyError: -1639031583
I create some stuff in the first test, and render a page. This leads to the recent items portlet to be rendered, and cached. Then I delete the stuff, and run the second test. Now the page including the portlet gets rendered again, and this causes the error - because the object is deleted, but still in some cache.
I first tried (a lot) to find ways to get hold of the PortletRenderer, which actually has the cache, but this didn't lead anywhere - inoking the portlet adapter magic machine didn't work as expected.
Finally (did I mention it: after lots of trying) I found that even though I can't delete the caches on the Renderers, the renderers themself are memoized. And they are stored in an annotation in the request object. So here is a little hack to get rid of the cached Renderers (or everything, as needed):
def cleanPortletCaches(content,selection=None): """ clean everything that causes catalog errors from the cache. This is a hack! """ request = content.REQUEST if not (hasattr(request,'__annotations__') and request.__annotations__.has_key('plone.memoize')): return cache = request.__annotations__['plone.memoize'] for key in [k for k in cache.keys() if 'ColumnPortletManagerRenderer' in str(k)]: # die grobschlaechtige Version: if selection is None: del(cache[key]) else: value = cache[key] newvalue = [entry for entry in value if entry['name'] not in selection] cache[key] = newvalue return def cleanAllCaches(content): request = content.REQUEST if not (hasattr(request,'__annotations__') and request.__annotations__.has_key('plone.memoize')): return del request.__annotations__['plone.memoize']