{ "info": { "author": "Plone Foundation", "author_email": "plone-developers@lists.sourceforge.net", "bugtrack_url": null, "classifiers": [ "Framework :: Plone", "Framework :: Plone :: 5.2", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "plone.cachepurging\n==================\n\n.. contents:: Table of Contents\n\n\nIntroduction\n------------\n\nThe ``plone.cachepurging`` package provides cache purging for Zope 2 applications.\nIt is inspired by (and borrows some code from) `Products.CMFSquidTool`_, but it\nis not tied to Squid. In fact, it is tested mainly with `Varnish`_, though it\nshould also work with `Squid`_ and `Enfold Proxy`_.\n\nThis package is not tied to Plone. However, if you intend to use it with\nPlone, you probably want to install `plone.app.caching`_, which provides\nPlone-specific configuration and a user interface in Plone's control panel.\n\n``plone.cachepurging`` works with Zope 2.12 and later. If you want to use it\nwith Zope 2.10, you may be able to do so by installing\n`ZPublisherEventsBackport`_, although this is not a tested configuration.\n\n\nInstallation\n------------\n\nTo use this package, you must do the following:\n\n* Install it into your Zope instance. This normally means depending on it\n via ``install_requires`` in the ``setup.py`` file of your package.\n\n* Load its configuration by adding a ZCML line like the following (or a slug)::\n\n \n\n* Install a `plone.registry`_ ``IRegistry`` local utility and create records\n for the interface ``plone.cachepurging.interfaces.ICachePurgingSettings``.\n See the ``plone.registry`` documentation for details.\n\nIf you use ``plone.app.caching`` in Plone, it will do all of this for you.\n\nTo enable cache purging after installation, you must:\n\n* Set up a caching proxy that supports PURGE requests, such as Varnish, Squid\n or Enfold Proxy.\n\n* Configure the proxy and your application so that resources are cached in the\n proxy.\n\n* Set the registry option ``plone.cachepurging.interfaces.ICachePurgingSettings.enabled``\n to ``True``. See the ``plone.registry`` documentation for details.\n\n* Add the URL of at least one caching proxy server capable of receiving PURGE\n requests to the registry option ``plone.cachepurging.interfaces.ICachePurgingSettings.cachingProxies``.\n This should be a URL that is reachable from the Zope server. It does not\n need to be accessible from Zope's clients.\n\n* Make your application send purge notifications - see below.\n\nInitiating a purge in code\n--------------------------\n\nThe simplest way to initiate a purge is to raise a ``Purge`` event::\n\n from z3c.caching.purge import Purge\n from zope.event import notify\n\n notify(Purge(context))\n\nNotice how we are actually importing from ``z3c.caching`` here. That package\ndefines the event type and a few of the interfaces that ``plone.cachepurging``\nuses. In most cases, you should be able to define how your own packages'\nbehave in relation to a caching proxy by depending on ``z3c.caching`` only.\nThis is a safer dependency, as it in turn depends only on a small set of\ncore Zope Toolkit packages.\n\nPresuming ``plone.cachepurging`` is installed, firing the event above will:\n\n* Check whether caching is enabled and configured. If not, it will do nothing.\n* Look up paths to purge for the given object. This is done via zero or more\n ``IPurgePaths`` adapters. See \"Which URLs get purged?\" below.\n* Convert the purge paths to URLs by combining them with the URLs of the\n configured caching proxies.\n* Queue these for purging.\n\nIt doesn't matter if a particular object or URLs is queued more than once.\nIt will only be executed once.\n\nThis operation is relatively quick, and does not involve communication with\nthe caching proxy. At the end of the request, after the Zope transaction has\nbeen closed (and presuming the transaction was successful - purging is by\ndefault not performed for requests resulting in an error), the following will\ntake place:\n\n* The queued URLs are retrieved from the request.\n* A worker thread is established for each caching proxy, allowing asynchronous\n processing and freeing up Zope to handle the next request.\n* The worker thread establishes a connection to the caching proxy and sends\n a PURGE request.\n* Any errors are logged at error level to the logger ``plone.cachepurging``.\n\nIf you need more control, you can perform the purging directly. Here is a\nsnippet adapted from the ``plone.cachepurging.purge`` view::\n\n from six import StringIO\n\n from zope.component import getUtility\n\n from plone.registry.interfaces import IRegistry\n\n from plone.cachepurging.interfaces import IPurger\n from plone.cachepurging.interfaces import ICachePurgingSettings\n\n from plone.cachepurging.utils import getPathsToPurge\n from plone.cachepurging.utils import getURLsToPurge\n from plone.cachepurging.utils import isCachePurgingEnabled\n\n ...\n\n if not isCachePurgingEnabled():\n return 'Caching not enabled'\n\n registry = getUtility(IRegistry)\n settings = registry.forInterface(ICachePurgingSettings)\n\n purger = getUtility(IPurger)\n\n out = StringIO()\n\n for path in getPathsToPurge(self.context, self.request):\n for url in getURLsToPurge(path, settings.cachingProxies):\n status, xcache, xerror = purger.purgeSync(url)\n print(\"Purged\", url, \"Status\", status, \"X-Cache\", xcache, \"Error:\", xerror, file=out)\n\n return out.getvalue()\n\nHere, we:\n\n* Check whether caching is enabled. This checks the ``enabled`` and\n ``cachingProxies`` properties in the registry.\n\n* Look up the registry and cache purging settings to find the list of\n caching proxies.\n\n* Obtain an ``IPurger`` utility. This has three main methods::\n\n def purgeAsync(url, httpVerb='PURGE'):\n \"\"\"Send a PURGE request to a particular URL asynchronously in a\n worker thread.\n \"\"\"\n\n def purgeSync(url, httpVerb='PURGE'):\n \"\"\"Send a PURGE request to a particular URL synchronosly.\n\n Returns a triple ``(status, xcache, xerror)`` where ``status`` is\n the HTTP status of the purge request, ``xcache`` is the contents of\n the ``x-cache`` response header, and ``x-error`` is the contents\n of the first header found from the list of headers in\n ``errorHeaders``.\n \"\"\"\n\n def stopThreads(wait=False):\n \"\"\"Attempts to stop all threads. Threads stop immediately after\n the current item is being processed.\n\n Returns True if successful, or False if threads are still running\n after waiting 5 seconds for each one.\n \"\"\"\n\n* Get all paths to purge for the current context using the helper function\n ``getPathsToPurge()``. Paths are relative to the domain root, i.e. they\n start with a '/'.\n\n* Obtain a full PURGE URL for each caching proxy, using the helper function\n ``getURLsToPurge()``\n\n* Send a synchronous caching request. This blocks until the caching proxy\n has responded (or timed out).\n\n\nPurging an object manually\n--------------------------\n\nThe code above illustrates how to initiate asynchronous and synchronous\npurges. If you simply want to do this through the web, you can invoke one\nof the following views, registered for any type of context:\n\n``@@plone.cachepurging.purge``\n Performs an immediate purge of the context, using code similar to that\n shown above.\n``@@plone.cachepurging.queue``\n Queues the context for purging.\n\nBoth of these views require the permission ``plone.cachepurging.InitiatePurge``,\nwhich by default is granted to the ``Manager`` role only.\n\n\nPurging objects automatically\n-----------------------------\n\nQuite commonly, you will want to purge objects in three scenarios:\n\n* When the object is modified\n* When the object is moved or renamed\n* When the object is removed\n\nThese are of course all described by standard Zope event types from the\n`zope.lifecycleevent`_ package. If the standard ``IObjectModifiedEvent``,\n``IObjectMovedEvent`` and ``IObjectRemovedEvent`` event types are fired for\nyour context, you can mark it with the ``IPurgeable`` interface to\nautomatically purge the object.\n\nOne way to do this without changing the code of your content object is to do\nthis in ZCML, e.g. with::\n\n \n \n \n\n(Again notice how we are using a generic interface from ``z3c.caching``).\n\nThis is equivalent to registering an event handler for each of the events\nabove and doing ``notify(Purge(object))`` in each one. That is, a\n``z3c.caching.interfaces.IPurgeEvent`` will be raised in a handler for the\nlifecycle events, which in turn will cause purging to take place.\n\n\nPurging dependencies\n--------------------\n\nSometimes, purging one object implies that other objects should be purged\nas well. One way to do this is to register an event handler for the\n``IPurgeEvent`` event type, and dispatch further purge events in response. For\nexample, here is some code to purge the parent of the purged object::\n\n from zope.component import adapter\n from z3c.caching.interfaces import IPurgeEvent\n from z3c.caching.purge import Purge\n\n @adapter(IMyContent, IPurgeEvent)\n def purgeParent(object, IPurgeEvent):\n parent = object.__parent__\n if parent is not None:\n notify(Purge(parent))\n\nThis could be registered in ZCML like so::\n\n \n\nIf the parent is also of type ``IMyContent`` (or you replace that interface\nwith a more generic one), then its parent will be purged too, recursively.\n\n\nWhich URLs get purged?\n----------------------\n\nThe ``Purge`` event handler calculates the URLs to purge for the object being\npassed via named ``z3c.caching.interfaces.IPurgePaths`` adapters. Any number\nof such adapters may be registered. ``plone.cachepurging`` ships with one, for\n``OFS.interfaces.ITraversable`` (i.e. most objects that you can find through\nthe ZMI), which purges the object's ``absolute_url_path()``.\n\nThe ``IPurgePaths`` interface looks like this::\n\n class IPurgePaths(Interface):\n \"\"\"Return paths to send as PURGE requests for a given object.\n\n The purging hook will look up named adapters from the objects sent to\n the purge queue (usually by an IPurgeEvent being fired) to this interface.\n The name is not significant, but is used to allow multiple implementations\n whilst still permitting per-type overrides. The names should therefore\n normally be unique, prefixed with the dotted name of the package to which\n they belong.\n \"\"\"\n\n def getRelativePaths():\n \"\"\"Return a list of paths that should be purged. The paths should be\n relative to the virtual hosting root, i.e. they should start with a\n '/'.\n\n These paths will be rewritten to incorporate virtual hosting if\n necessary.\n \"\"\"\n\n def getAbsolutePaths():\n \"\"\"Return a list of paths that should be purged. The paths should be\n relative to the domain root, i.e. they should start with a '/'.\n\n These paths will *not* be rewritten to incorporate virtual hosting.\n \"\"\"\n\nMost implementations will use ``getRelativePaths()`` to return a path relative\nto the virtual hosting root (i.e. what the ``absolute_url_path()`` method\nreturns). This is subject to rewriting for virtual hosting (see below).\n\n``getAbsolutePaths()`` is useful if you have a path that is not subject to\nchange no matter how Zope is configured. For example, you could use this if\nyour caching proxy supports \"special\" URLs to invoke a particular type of\npurge. (Such behaviour can be implemented in Varnish using VCL, for example.)\nThis is *not* subject to rewriting for virtual hosting.\n\nLet's say you wanted to always purge the URL ``${object_url}/view`` for any\nobject providing ``IContentish`` from CMF. A simple implementation may look\nlike this::\n\n from zope.interface import implementer\n from zope.component import adapts\n\n from z3c.caching.interfaces import IPurgePaths\n\n from Products.CMFCore.interfaces import IContentish\n\n @implementer(IPurgePaths)\n class ObjectViewPurgePaths(object):\n \"\"\"Purge /view for any content object with the content object's\n default URL\n \"\"\"\n\n adapts(IContentish)\n\n def __init__(self, context):\n self.context = context\n\n def getRelativePaths(self):\n return [self.context.absolute_url_path() + '/view']\n\n def getAbsolutePaths(self):\n return []\n\nThis adapter could be registered with a ZCML statement like::\n\n \n\nThe name is not significant, but should be unique unless it is intended to\noverride an existing adapter. By convention, you should prefix the name with\nyour package's dotted name unless you have a reason not to.\n\nThe default adapter thats simply returns ``absolute_url_path()`` is called\n``default``.\n\n\nVirtual hosting and URL rewriting\n----------------------------------\n\nZope 2 uses \"magic\" URLs for virtual hosting. A common scenario is to set\nthe virtual host root to a Plone site object at the root of the Zope instance.\nThis is usually done through URL rewriting. The user sees a URL like\n``http://example.com/front-page``. A web server like Apache (or a proxy like\nSquid or Varnish) changes this into a URL like this::\n\n http://localhost:8080/VirtualHostBase/http/example.com:80/Plone/VirtualHostRoot/front-page\n\nHere, the Zope server is running on ``http://localhost:8080``, the external\ndomain is ``http://example.com:80`` (the ``:80`` part is normally not shown\nby web browsers, since that is the default protocol for the ``http`` URL\nscheme), and the virtual hosting root is ``/Plone``.\n\nZope sees these tokens in the URL and understands how to incorporate the\nexternal domain and virtual host root into the results of methods like\n``absolute_url()`` and ``absolute_url_path()``, thus allowing URLs generated\nin the site to show the correct external URL.\n\nSo far so good. The challenge comes when you put a caching proxy into the mix.\nThere are two scenarios:\n\n1. The caching proxy is \"behind\" whatever performs the URL rewrite. In this\n case, the inbound URL (which the proxy may choose to cache, and which may\n therefore need to be purged) contains the virtual hosting tokens.\n2. The caching proxy is \"in front of\" whatever performs the URL rewrite, or\n performs the rewrite before passing the request off to the Zope backend.\n In this case, the inbound URL does not contain the virtual hosting tokens.\n\nPurging works by sending the proxy server a ``PURGE`` request with the same\npath as that of a cached resource. Thus, in scenario 1, that URL needs to\ncontain the virtual hosting tokens. Since these are not part of any URL\ngenerated by Zope (though they are retained in the ``PATH_INFO`` request\nvariable), the paths returned by ``getRelativePaths()`` of the ``IPurgePaths``\nadapters need to be rewritten (in reverse, as it were) to include them.\n\nThis is done using an ``IPurgePathRewriter`` adapter on the request. The\ndefault implementation will deal with any valid VirtualHostMonster URL,\nincluding setups using \"inside-out\" hosting (with ``_vh_`` type path\nsegments), although you can write your own adapter if you have truly unique\nneeds.\n\nIf you perform URL rewriting in front of the caching proxy (scenario 1 above),\nyou need to configure two registry options, since there is no way for\n``plone.cachepurging`` to know how the web and/or proxy cache server(s) in\nfront of Zope are configured:\n\n``plone.cachepurging.interfaces.ICachePurgingSettings.virtualHosting``\n Set this to ``True`` to incorporate virtual hosting tokens in the\n PURGE paths. This is applicable in scenario 1 above.\n``plone.cachepurging.interfaces.ICachePurgingSettings.domains``\n Set this to a tuple of domains `including` ports (e.g.\n ``('http://example.com:80`, 'http://www.example.com:80',)``) if your site\n is served on multiple domains. This is useful because the virtual hosting\n URL contains the \"external\" domain name. If your site is hosted such\n that it can be reached via multiple domains (e.g. ``http://example.com``\n vs. ``http://www.example.com``), the virtual hosting path will be\n different depending on which one the user happened to use. Most likely,\n you will want to purge *both* variants.\n\n Note that it is probably better to normalise your paths in the fronting\n web server, so that Zope only ever sees a single external domain. If you\n only have one domain, or if the ``virtualHosting`` option is false, you do\n not need to set this option.\n\n.. _Products.CMFSquidTool: http://pypi.python.org/pypi/Products.CMFSquidTool\n.. _Squid: http://squid-cache.org\n.. _Varnish: http://varnish-cache.org\n.. _Enfold Proxy: http://enfoldsystems.com/software/proxy/\n.. _plone.app.caching: http://pypi.python.org/pypi/plone.app.caching\n.. _ZPublisherEventsBackport: http://pypi.python.org/pypi/ZPublisherEventsBackport\n.. _plone.registry: http://pypi.python.org/pypi/plone.registry\n.. _zope.lifecycleevent: http://pypi.python.org/pypi/zope.lifecycleevent\n\nChangelog\n=========\n\n2.0.1 (2018-12-11)\n------------------\n\nBreaking changes:\n\n- Remove five.globalrequest dependency.\n It has been deprecated upstream (Zope 4).\n [gforcada]\n\nBug fixes:\n\n- Avoid a ResourceWarning: unclosed socket.\n [gforcada]\n\n2.0 (2018-10-31)\n----------------\n\nBreaking changes:\n\n- Use `requests `_ library instead of handcrafting connection and requests on our own.\n This avoids strange problems in real-world customers environments.\n We do not need to reinvent the wheel here.\n Requests always uses HTTP 1.1 and drops support for HTTP 1.0 only caches.\n [jensens]\n\nNew features:\n\n- Try to avoid port collisions when running tests.\n [gforcada]\n\nBug fixes:\n\n- Set default purger backlog size to 0 (infinity) in order to fully invalidate Varnish cache\n [avoinea refs #11]\n\n- Tests and Code are Python 3 compatible\n [pbauer, ale-rt, jensens]\n\n\n1.0.15 (2018-04-24)\n-------------------\n\nBug fixes:\n\n- consider purging to be enabled when it's enabled (even if no servers are listed)\n [skurfer]\n\n\n1.0.14 (2018-01-30)\n-------------------\n\nBug fixes:\n\n- Add Python 2 / 3 compatibility\n [pbauer]\n\n\n1.0.13 (2016-10-04)\n-------------------\n\nBug fixes:\n\n- Code-Style: isort, utf8-headers, zca-decorators, manual cleanup.\n [jensens]\n\n\n1.0.12 (2016-08-08)\n-------------------\n\nNew features:\n\n- Use zope.interface decorator.\n [gforcada]\n\n\n1.0.11 (2016-01-08)\n-------------------\n\nFixes:\n\n- Fixed typo.\n [ale-rt]\n\n\n1.0.10 (2015-11-28)\n-------------------\n\nFixes:\n\n- Changed i18n_domain to \"plone\".\n [staeff]\n\n\n1.0.9 (2015-07-18)\n------------------\n\n- Do not iterate on settings.cachingProxies when there are no.\n [gotcha]\n\n\n1.0.8 (2015-06-09)\n------------------\n\n- correctly be able to purge empty path(root of site). Previously, /\n was always appended to url so one potential path of the resource\n in varnish would never get purged--sometimes the most important, the homepage.\n [vangheem]\n\n\n1.0.7 (2014-09-11)\n------------------\n\n- Fix installation issues due to missing commas in setup.py\n [esteele]\n\n\n1.0.6 (2014-09-08)\n------------------\n\n- Add undeclared dependencies\n [gforcada]\n\n\n1.0.5 (2013-12-07)\n------------------\n\n- Replace deprecated test assert statements.\n [timo]\n\n\n1.0.4 (2012-12-09)\n------------------\n\n- Fixed purge paths for virtual hosting scenarios using virtual path components.\n [dokai]\n\n\n1.0.3 (2011-09-16)\n------------------\n\n- Only import ssl module when purging an https url, closes #12190.\n [elro]\n\n1.0.2 (2011-08-31)\n------------------\n\n- Cast wait_time to int before calling xrange. This fixes\n \"TypeError: integer argument expected, got float\" error.\n [vincentfretin]\n\n\n1.0.1 - 2011-05-21\n------------------\n\n- Register a `zope.testing.cleanup.addCleanUp` function to stop all purge\n threads. Also make the default purger available as a module global, so the\n cleanup function can get to it after the ZCA has been torn down.\n [hannosch]\n\n- Register an atexit handler to stop the purge thread on process shutdown.\n [hannosch]\n\n- Change the reconnect strategy for the purge thread to retry fewer times and\n assume a permanent connection failure after one minute and stop the thread.\n This allows the application process to shutdown cleanly without the purge\n thread being stuck forever.\n [hannosch]\n\n- Update socket connection code for the purge thread to use Python 2.6 support\n for passing in a timeout to the create_connection call.\n [hannosch]\n\n- Disable `purge queue is full` warning in debug mode, where it spammed the\n console.\n [hannosch]\n\n- Correct license and update distribution metadata.\n [hannosch]\n\n\n1.0 - 2011-05-13\n----------------\n\n- Release 1.0 Final.\n [esteele]\n\n- Add MANIFEST.in.\n [WouterVH]\n\n\n1.0b2 - 2011-04-06\n------------------\n\n- Fix package requirements to pull in plone.app.testing as part of the [test]\n extra.\n [esteele]\n\n\n1.0b1 - 2010-12-14\n-------------------\n\n- Fix rewriting of paths in a virtual hosting environment, so that the path passed\n to the rewriter is actually used instead of always the current request path.\n [davisagli]\n\n\n1.0a1 - 2010-04-22\n------------------\n\n- Initial release\n [optilude, newbery]\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://pypi.org/project/plone.cachepurging", "keywords": "plone cache purge", "license": "GPL version 2", "maintainer": "", "maintainer_email": "", "name": "plone.cachepurging", "package_url": "https://pypi.org/project/plone.cachepurging/", "platform": "", "project_url": "https://pypi.org/project/plone.cachepurging/", "project_urls": { "Homepage": "https://pypi.org/project/plone.cachepurging" }, "release_url": "https://pypi.org/project/plone.cachepurging/2.0.1/", "requires_dist": [ "setuptools", "plone.registry", "requests", "six", "z3c.caching", "zope.annotation", "zope.component", "zope.event", "zope.i18nmessageid", "zope.interface", "zope.lifecycleevent", "zope.schema", "zope.testing", "Zope2", "plone.app.testing; extra == 'test'" ], "requires_python": "", "summary": "Cache purging support for Zope 2 applications", "version": "2.0.1" }, "last_serial": 4585459, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "be710502dbd6cde75134808cff5029d1", "sha256": "ab6d2b9c903b4b44c00eb549a59760d7813f07d34deb592c68752735ccdec7e0" }, "downloads": -1, "filename": "plone.cachepurging-1.0.zip", "has_sig": false, "md5_digest": "be710502dbd6cde75134808cff5029d1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 81283, "upload_time": "2011-05-13T17:41:27", "url": "https://files.pythonhosted.org/packages/3c/df/39881335a4d66cd0a3c733bed0b6391ce487919facb5716593c826fa9517/plone.cachepurging-1.0.zip" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "c7a79eb879615fcae36da8d208ee9001", "sha256": "5c792bfea87fd772b6dfbb2b15f2cab70bbacb8fdf23727f06154826f666da35" }, "downloads": -1, "filename": "plone.cachepurging-1.0.1.zip", "has_sig": false, "md5_digest": "c7a79eb879615fcae36da8d208ee9001", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 50798, "upload_time": "2011-05-21T18:06:02", "url": "https://files.pythonhosted.org/packages/8c/0a/abaa1e0c9461588864969fac3d0bf81f98ea7e7e88dd398e27d9246da6bb/plone.cachepurging-1.0.1.zip" } ], "1.0.10": [ { "comment_text": "", "digests": { "md5": "d4f58378dcb5d306942da263ba224432", "sha256": "f5e1aff65ad71a574c32b66988b5871605559d86189001acd493c3e494cb7466" }, "downloads": -1, "filename": "plone.cachepurging-1.0.10.tar.gz", "has_sig": false, "md5_digest": "d4f58378dcb5d306942da263ba224432", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36322, "upload_time": "2015-11-27T23:46:33", "url": "https://files.pythonhosted.org/packages/c7/ba/16ebe7466b6de149ef2ef15be855e62f8dccae3ba38720a43d5853ebb608/plone.cachepurging-1.0.10.tar.gz" } ], "1.0.11": [ { "comment_text": "", "digests": { "md5": "374b3d574d631849d350b47ad75ea856", "sha256": "acf8bc41ea065e7fd23a8ce498385bcaba56434b461495176c7b795364d88c27" }, "downloads": -1, "filename": "plone.cachepurging-1.0.11.tar.gz", "has_sig": false, "md5_digest": "374b3d574d631849d350b47ad75ea856", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36393, "upload_time": "2016-01-08T12:35:54", "url": "https://files.pythonhosted.org/packages/b5/5d/d42dbaed8311e2845364a7fb165e20578ce946b19ff566fbee920a9888b7/plone.cachepurging-1.0.11.tar.gz" } ], "1.0.12": [ { "comment_text": "", "digests": { "md5": "203d2835c8b3f8774269d7d0e101e69d", "sha256": "093b79a18c00d1f1e9d321ae5e09a07f1a8ec89c9aa38ac19d5f34a261f023bf" }, "downloads": -1, "filename": "plone.cachepurging-1.0.12.tar.gz", "has_sig": false, "md5_digest": "203d2835c8b3f8774269d7d0e101e69d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36483, "upload_time": "2016-08-08T16:07:49", "url": "https://files.pythonhosted.org/packages/61/38/87d8dd85e08a666450d4e050ee9ab1c1773841cf88e4bac1dc88d161f1b7/plone.cachepurging-1.0.12.tar.gz" } ], "1.0.13": [ { "comment_text": "", "digests": { "md5": "1389d4d010aace9cd0bf4e58d2b9f7a3", "sha256": "94ec3e27a95a9c0f8328a1cd3de77becb10dafae006694f28c1292c7930442e2" }, "downloads": -1, "filename": "plone.cachepurging-1.0.13.tar.gz", "has_sig": false, "md5_digest": "1389d4d010aace9cd0bf4e58d2b9f7a3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36874, "upload_time": "2016-10-04T16:43:32", "url": "https://files.pythonhosted.org/packages/8a/76/f09e06ed08b087868fbd11df49bb516d919bf35e22df4adfa2ab4da518bc/plone.cachepurging-1.0.13.tar.gz" } ], "1.0.14": [ { "comment_text": "", "digests": { "md5": "7ea925e096d6fe885908169980c5dbb7", "sha256": "d8922fe3cdda90b44b52dbc688b807d3fe661ce7061474092f0c19edbcd25e74" }, "downloads": -1, "filename": "plone.cachepurging-1.0.14-py2-none-any.whl", "has_sig": false, "md5_digest": "7ea925e096d6fe885908169980c5dbb7", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 36659, "upload_time": "2018-01-30T09:53:00", "url": "https://files.pythonhosted.org/packages/f5/b1/b89a4994253e2ad10e4c0ed77d29ea7318e5a58a3477c6db180fa57599f4/plone.cachepurging-1.0.14-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d864546fedea24cad3b2095ebad9ac25", "sha256": "8cc58bee54dbf98c77e75f71d117b620730fa287854f80611f963d352f73993c" }, "downloads": -1, "filename": "plone.cachepurging-1.0.14.tar.gz", "has_sig": false, "md5_digest": "d864546fedea24cad3b2095ebad9ac25", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35371, "upload_time": "2018-01-30T09:53:03", "url": "https://files.pythonhosted.org/packages/b6/a9/7a464896a43e8d1228cf63a5874bd78faea52a4648941702ed42230959cf/plone.cachepurging-1.0.14.tar.gz" } ], "1.0.15": [ { "comment_text": "", "digests": { "md5": "dc2b2729cbf41af29d97694e3d7fafb5", "sha256": "a2816cb42e73c5ff3942a1a1969bdd8ca4f999247dcf4f3c2d82959422a1c12f" }, "downloads": -1, "filename": "plone.cachepurging-1.0.15-py2-none-any.whl", "has_sig": false, "md5_digest": "dc2b2729cbf41af29d97694e3d7fafb5", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 36706, "upload_time": "2018-04-24T16:03:33", "url": "https://files.pythonhosted.org/packages/af/ff/9e36bd755c2845630fc344d8b8e997ce077596c281a305d497be741c69d5/plone.cachepurging-1.0.15-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "04f36d87b6481da6a858001252017dea", "sha256": "9c730b3c273a7d83f7dfe58d4defabfa1864482d7db42fa4acd71f800eb2dfbc" }, "downloads": -1, "filename": "plone.cachepurging-1.0.15.tar.gz", "has_sig": false, "md5_digest": "04f36d87b6481da6a858001252017dea", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35459, "upload_time": "2018-04-24T16:03:34", "url": "https://files.pythonhosted.org/packages/c1/95/2b11ea1f19063b11d7cd870f65dda553359f04aa7e78038a756842f80f46/plone.cachepurging-1.0.15.tar.gz" } ], "1.0.16": [ { "comment_text": "", "digests": { "md5": "feccf358b2b50abf296a30d433153e70", "sha256": "13ed4e868b840cad4ad9aab122128f92a3201faa035915c06c83966bc2ec7c0d" }, "downloads": -1, "filename": "plone.cachepurging-1.0.16-py2-none-any.whl", "has_sig": false, "md5_digest": "feccf358b2b50abf296a30d433153e70", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 28566, "upload_time": "2018-09-26T16:31:41", "url": "https://files.pythonhosted.org/packages/01/f1/5f4cdf7f9359586fa849ad40f20af1cdf5f29eba4598bf46911f5a4d0d2b/plone.cachepurging-1.0.16-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "edb50b84073f9d4b54209bff6de7e517", "sha256": "883e5bc8c1fadf18ac6ed5fb915804e6e9951f85c8ce8cd8af843646b1d1f617" }, "downloads": -1, "filename": "plone.cachepurging-1.0.16.tar.gz", "has_sig": false, "md5_digest": "edb50b84073f9d4b54209bff6de7e517", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35774, "upload_time": "2018-09-26T16:31:43", "url": "https://files.pythonhosted.org/packages/c1/f9/a7472aeb4e17d9d8d6f1d6023726f3d48397c6357e5057b06c61ea8fd34c/plone.cachepurging-1.0.16.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "c3302300ba6892727e80f31272109f21", "sha256": "050c86bf7107b3958638e1fce7d988b24d3766963b5b42be3fd07a90c6d0fb39" }, "downloads": -1, "filename": "plone.cachepurging-1.0.2.tar.gz", "has_sig": false, "md5_digest": "c3302300ba6892727e80f31272109f21", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30598, "upload_time": "2011-09-01T03:32:29", "url": "https://files.pythonhosted.org/packages/47/5b/6d86c7cfe7a889e7d86f1307fcca7bb992d28d65110f7a0625e45bb1d39b/plone.cachepurging-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "26d47c4e2dccfb1992feb259e7e01c11", "sha256": "867198c9c30bf8eccb7f8bed55640d921b29d43c37536538c1a8bf7837c518e8" }, "downloads": -1, "filename": "plone.cachepurging-1.0.3.tar.gz", "has_sig": false, "md5_digest": "26d47c4e2dccfb1992feb259e7e01c11", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30736, "upload_time": "2011-09-16T16:31:52", "url": "https://files.pythonhosted.org/packages/c5/0e/6c81e09fb4e3725179c0269d287f388252cc1a072c9ac49acaff84369860/plone.cachepurging-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "886814ac4deef0f1ed99a2eb60864264", "sha256": "fdcbd970e2bb3ae6b208db90f2d37c8ccb7230170357fb356af6cf4920da2646" }, "downloads": -1, "filename": "plone.cachepurging-1.0.4.zip", "has_sig": false, "md5_digest": "886814ac4deef0f1ed99a2eb60864264", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51407, "upload_time": "2012-12-10T02:17:43", "url": "https://files.pythonhosted.org/packages/aa/07/0109f6b523a0b2f26ab78200ea7904cb91b833b8a5e9fff486d4c23479f0/plone.cachepurging-1.0.4.zip" } ], "1.0.5": [ { "comment_text": "", "digests": { "md5": "ae893d47c424cb8a4cd688f6d9b46dc0", "sha256": "149b654a0d423ee467eb3dba502ba5d98c86a97fdc595eb324d0c55513f0d807" }, "downloads": -1, "filename": "plone.cachepurging-1.0.5.zip", "has_sig": false, "md5_digest": "ae893d47c424cb8a4cd688f6d9b46dc0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51736, "upload_time": "2013-12-08T02:43:45", "url": "https://files.pythonhosted.org/packages/3a/1a/436b00c092d5837df5e9d944e2ff5fc109a944683540bfbb022a886ced0c/plone.cachepurging-1.0.5.zip" } ], "1.0.6": [ { "comment_text": "", "digests": { "md5": "5fa40e32344cd6f5cf3d1d7b3aac078e", "sha256": "303eaa625d3c11ed693df6f5cd449047d0732f7af2765f0ada7c880586b12a0a" }, "downloads": -1, "filename": "plone.cachepurging-1.0.6.zip", "has_sig": false, "md5_digest": "5fa40e32344cd6f5cf3d1d7b3aac078e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51767, "upload_time": "2014-09-08T15:18:40", "url": "https://files.pythonhosted.org/packages/01/2a/107ddd88fc43c6b8f243ed0649950eaa088af1d35c4373364d2f87b596dc/plone.cachepurging-1.0.6.zip" } ], "1.0.7": [ { "comment_text": "", "digests": { "md5": "bcff39ad707bfbdeb96d87ae0b37e136", "sha256": "7847bc81e5a49c95341a8347b88c9525ca01c7fe19f0aba1aabda0f5d1307bc6" }, "downloads": -1, "filename": "plone.cachepurging-1.0.7.zip", "has_sig": false, "md5_digest": "bcff39ad707bfbdeb96d87ae0b37e136", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51869, "upload_time": "2014-09-11T19:41:11", "url": "https://files.pythonhosted.org/packages/32/6b/c9ae4276bbdc3b1765de800568802fcdcbdfd4522ca0e76225495d3fb91b/plone.cachepurging-1.0.7.zip" } ], "1.0.8": [ { "comment_text": "", "digests": { "md5": "baffe05b0290903781a6c7395c708627", "sha256": "aeb8d49da662b52bc84658db4e7131c909cf515d45ee2d537b320fac410232f6" }, "downloads": -1, "filename": "plone.cachepurging-1.0.8.tar.gz", "has_sig": false, "md5_digest": "baffe05b0290903781a6c7395c708627", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35861, "upload_time": "2015-06-09T15:15:34", "url": "https://files.pythonhosted.org/packages/0d/7e/41c48f5688218e69d34ab5c76277912c3830bbfa3d9614f379d0dc797f5f/plone.cachepurging-1.0.8.tar.gz" } ], "1.0.9": [ { "comment_text": "", "digests": { "md5": "81af06b5d4959219121daa63bab3c59c", "sha256": "103c2638bb68d4c8a642b0118abc834fa59c0e90fa53e7fc5a8b4106c2158230" }, "downloads": -1, "filename": "plone.cachepurging-1.0.9.tar.gz", "has_sig": false, "md5_digest": "81af06b5d4959219121daa63bab3c59c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35993, "upload_time": "2015-07-18T08:01:34", "url": "https://files.pythonhosted.org/packages/f1/96/67d5556c5f4200a7212a3abfd76aeb67a68a2dd3969b0971e0f71f0ec65c/plone.cachepurging-1.0.9.tar.gz" } ], "1.0a1": [ { "comment_text": "", "digests": { "md5": "d5030ac617d9b124a9ac92f87ee16d21", "sha256": "7916ded9ee0404847a4f0ecd6f4f82497249f81853c7e7e25c4b0f68064480f7" }, "downloads": -1, "filename": "plone.cachepurging-1.0a1.tar.gz", "has_sig": false, "md5_digest": "d5030ac617d9b124a9ac92f87ee16d21", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33806, "upload_time": "2010-04-22T13:24:19", "url": "https://files.pythonhosted.org/packages/71/54/a4d944d8f2de57fa0889453172435133bf831d12b768a7f8bbdbb72ecb4d/plone.cachepurging-1.0a1.tar.gz" } ], "1.0b1": [ { "comment_text": "", "digests": { "md5": "afccda67c2c47bae31b77d337ca6ca97", "sha256": "a1870aa8ac53f19cb7f261900b40386a5a228c74be14b9822e1e386731ac3f54" }, "downloads": -1, "filename": "plone.cachepurging-1.0b1.zip", "has_sig": true, "md5_digest": "afccda67c2c47bae31b77d337ca6ca97", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51074, "upload_time": "2010-12-14T21:54:16", "url": "https://files.pythonhosted.org/packages/a2/ce/a4cfeb81a31c97744d47f65f52565443c461d1203d5f04280507685cb987/plone.cachepurging-1.0b1.zip" } ], "1.0b2": [ { "comment_text": "", "digests": { "md5": "f031780b00cf8c4374b173ef84f7c857", "sha256": "70c47ad0e9089306d268ca5ff091e7cd5e60b40c0aeb90f8cd79b3f8d8715da3" }, "downloads": -1, "filename": "plone.cachepurging-1.0b2.zip", "has_sig": false, "md5_digest": "f031780b00cf8c4374b173ef84f7c857", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51088, "upload_time": "2011-04-07T01:19:01", "url": "https://files.pythonhosted.org/packages/cc/3f/effb0587904fa652a98ae1038bb1026c5508192c51ef8c1aa87d0c3312df/plone.cachepurging-1.0b2.zip" } ], "2.0": [ { "comment_text": "", "digests": { "md5": "47f643c6c389534f7ca2c80cd0b0bb85", "sha256": "ce28cf0a39333dd0bdb4f2f306b499d62008c1e0b1622959ee8678c5ef647f2d" }, "downloads": -1, "filename": "plone.cachepurging-2.0-py2-none-any.whl", "has_sig": false, "md5_digest": "47f643c6c389534f7ca2c80cd0b0bb85", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 36059, "upload_time": "2018-11-01T01:41:38", "url": "https://files.pythonhosted.org/packages/35/cf/90374382c4c885e34a4903e60d965cf4ba606d7332902e116822819b77e1/plone.cachepurging-2.0-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a6296a5f5cc7411c18e9da045ba8ab51", "sha256": "dc920ef981567c029590c165c9947341bbdfa3affa6ba0d05af37f5809118c0f" }, "downloads": -1, "filename": "plone.cachepurging-2.0.tar.gz", "has_sig": false, "md5_digest": "a6296a5f5cc7411c18e9da045ba8ab51", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34988, "upload_time": "2018-11-01T01:41:40", "url": "https://files.pythonhosted.org/packages/34/ea/f8082c204dea2eb10d10fee8e967d2a86f58ca9cabba9d6983141ff07206/plone.cachepurging-2.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "792d14eddba92f99f425c93897b22e2c", "sha256": "762caf125cb7f53c5cb2f9c4e411becf000c6bb8384b0e8f8391bd89176ccba9" }, "downloads": -1, "filename": "plone.cachepurging-2.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "792d14eddba92f99f425c93897b22e2c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 27561, "upload_time": "2018-12-11T13:37:48", "url": "https://files.pythonhosted.org/packages/c5/0d/0c8c7e89b5ab47da5d0419d250324f9f067442c318e348220db6fc4e8ab3/plone.cachepurging-2.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f5e44514a141e702c4467eaf1f891917", "sha256": "cca838443230c9140f733ed4440d894ebae17b3a90fa511c0a204366ff037841" }, "downloads": -1, "filename": "plone.cachepurging-2.0.1.tar.gz", "has_sig": false, "md5_digest": "f5e44514a141e702c4467eaf1f891917", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37962, "upload_time": "2018-12-11T13:37:49", "url": "https://files.pythonhosted.org/packages/03/60/5c699299781bc2b54fd11274a11f0b0ef86f4b03ef4c44189abb4c55612c/plone.cachepurging-2.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "792d14eddba92f99f425c93897b22e2c", "sha256": "762caf125cb7f53c5cb2f9c4e411becf000c6bb8384b0e8f8391bd89176ccba9" }, "downloads": -1, "filename": "plone.cachepurging-2.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "792d14eddba92f99f425c93897b22e2c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 27561, "upload_time": "2018-12-11T13:37:48", "url": "https://files.pythonhosted.org/packages/c5/0d/0c8c7e89b5ab47da5d0419d250324f9f067442c318e348220db6fc4e8ab3/plone.cachepurging-2.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f5e44514a141e702c4467eaf1f891917", "sha256": "cca838443230c9140f733ed4440d894ebae17b3a90fa511c0a204366ff037841" }, "downloads": -1, "filename": "plone.cachepurging-2.0.1.tar.gz", "has_sig": false, "md5_digest": "f5e44514a141e702c4467eaf1f891917", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37962, "upload_time": "2018-12-11T13:37:49", "url": "https://files.pythonhosted.org/packages/03/60/5c699299781bc2b54fd11274a11f0b0ef86f4b03ef4c44189abb4c55612c/plone.cachepurging-2.0.1.tar.gz" } ] }