{
"info": {
"author": "Jim Fulton",
"author_email": "jim@zope.com",
"bugtrack_url": null,
"classifiers": [
"Framework :: ZODB",
"License :: OSI Approved :: Zope Public License",
"Operating System :: Microsoft :: Windows",
"Operating System :: Unix",
"Programming Language :: Python",
"Topic :: Database",
"Topic :: Software Development :: Libraries :: Python Modules"
],
"description": "==============\nBefore Storage\n==============\n\nZODB storages typically store multiple object revisions to support\nfeatures such as multi-version concurrency control and undo. In the\ncase of the mod popular storage implementation, old revisions aren't\ndiscarded until a pack. This feature has often been exploited to\nperform time travel, allowing one to look at a database as it existed\nin at some point in time. In the past, this has been possible with\nfile storage by specifying a time at which to open the file\nstorage. This works fairly well, but is very slow for large databases\nbecause existing index files can't easily be used. Time travel is\nalso supported for individual objects through the ZODB history\nmechanism.\n\nThe introduction of multi-version concurrency control provided new\nopertunities for time travel. Using the storage loadBefore method,\none can load transaction records written before a given time. ZODB\n3.9 will provide an option to the database open method for opening\nconnections as of a point in time.\n\nDemo storage can be quite useful for testing, and especially staging\napplications. In a common configuration, they allow for storing\nchanges to a base database without changing the underlying database.\nZope functional testing frameworks leverage demo storages to easily\nroll-back database state after a test to a non-empty state before a\ntest. A significant limitation of demo storages is that they can't be\nused with base storages that change. This means that they generaly\ncan't be used with ZEO. It isn't enough to have a read-only\nconnections, if the underlying database is still being changed by\nother clients.\n\nThe \"before\" storage provides another way to leverage the loadBefore\nmethod to support time travel and a means to provide an unchanging\nview into a ZEO server. A before storage is a database adapter that\nprovides a read-only view of an underlying storage as of a particular\npoint in time.\n\nChange history\n==============\n\n\n0.5.1 (2013-10-25)\n------------------\n\n- Fix broken release\n\n\n0.5.0 (2013-10-25)\n------------------\n\nAdded ZODB4 and Python 3 support.\n\n\n0.4.0 (2010-12-09)\n------------------\n\nAdded a \"before-from-file\" option that can be used if the application wants to\npreserve beforestorage state between application restarts.\n\n0.3.2 (2008-12-05)\n------------------\n\nUpdated to work with both ZODB 3.8 and 3.9.\n\n0.3.1 (2008-12-01)\n------------------\n\nRenamed lastTid to getTid to conform to the ZEO.interfaces.IServeable\ninterface.\n\n\n0.3.0 (2008-12-01)\n------------------\n\nAdded Blob support.\n\n0.2.0 (2008-03-05)\n------------------\n\nAdded support for \"now\" and \"startup\" values to the before option when\nusing ZConfig. The \"now\" value indicates that the before storage should\nprovide a view of the base storage as of the time the storage is created.\nThe \"startup\" value indicates that the before storage should provide a\nview of the base stoage as of process startup time. The later is\nespecially useful when setting up more than once before storage in a\nsingle application, as it allows you to arrange that all of the\nstorages provide consistent views without having to specify a time.\n\n0.1.1 (2008-02-07)\n------------------\n\nFixed a packaging bug that caused some files to be omitted.\n\n0.1 (2008-01-??)\n----------------\n\nInitial release.\n\nUsing ZConfig to configure Before storages\n==========================================\n\n\"before\" option\n---------------\n\nTo use before storages from ZConfig configuration files, you need to\nimport zc.beforestorage and then use a before storage section.\n\n >>> import ZODB.config\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %import zc.beforestorage\n ...\n ... \n ... before 2008-01-21\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\")\n\n >>> storage\n \n\n >>> storage.close()\n\nIf we leave off the before option, we'll use the current time:\n\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %import zc.beforestorage\n ...\n ... \n ... \n ... path my.fs\n ... \n ... \n ... \"\"\")\n\n >>> storage\n \n\n >>> storage.close()\n\nWe can also give the option 'now' and get the current time.\n\n >>> import ZODB.config\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %import zc.beforestorage\n ...\n ... \n ... before now\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\")\n\n >>> storage\n \n\n >>> storage.close()\n\nWe can give the option 'startup' and get the time at startup.\n\n >>> import ZODB.config\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %import zc.beforestorage\n ...\n ... \n ... before startup\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\")\n\n >>> storage\n \n >>> import zc.beforestorage\n >>> import ZODB.TimeStamp\n >>> print(\n ... str(zc.beforestorage.startup_time_stamp))\n 2008-01-21 18:22:43.000000\n >>> storage.close()\n\n\n\"before-from-file\" option\n-------------------------\n\nThe \"before-from-file\" option can be used to preserve the changes file between\nrestarts. It's value is the absolute path to a file. If the file exists, the\n\"before\" time will be read from that file. If the file does not exist,\nit will be created and the current UTC time will be written to it\n\nWhen used with a Changes file that does NOT have the \"create=true\"\noption set, the database will be preserved between restarts.\n\n >>> import os.path\n >>> import tempfile\n\n >>> tempdir = tempfile.mkdtemp()\n >>> before_file = os.path.join(tempdir, 'before-file')\n\nCurrently the file does not exist. So it'll be created and written with the\ncurrent time. In order to make this repeatable, we \"monkeypatch\" the \"get_now\"\nfunction in the module to return a fixed value:\n\n >>> import datetime\n >>> import zc.beforestorage\n\n >>> def fake_get_utcnow():\n ... return datetime.datetime(2008, 1, 1, 15, 0)\n >>> orig_get_utcnow = zc.beforestorage.get_utcnow\n >>> zc.beforestorage.get_utcnow = fake_get_utcnow\n\n >>> os.path.exists(before_file)\n False\n\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %%import zc.beforestorage\n ...\n ... \n ... before-from-file %s\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\" % before_file)\n\n >>> storage\n \n\n >>> storage.close()\n\nThe file will now have been created:\n\n >>> os.path.exists(before_file)\n True\n\n >>> f = open(before_file)\n >>> f.read() == fake_get_utcnow().replace(microsecond=0).isoformat()\n True\n\nIf we now write a new value to the file, the storage will be started with that\ntime.\n\n >>> f = open(before_file, 'w')\n >>> _ = f.write('1990-01-01T11:11')\n >>> f.close()\n\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %%import zc.beforestorage\n ...\n ... \n ... before-from-file %s\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\" % before_file)\n\n >>> storage\n \n\n >>> storage.close()\n\nIf we restart the storage, the value from the file will be used.\n\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %%import zc.beforestorage\n ...\n ... \n ... before-from-file %s\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\" % before_file)\n\n >>> storage\n \n\n >>> storage.close()\n\nThis will continue to happen until we remove the file. The \"before_from_file\"\npath is stored on the storage itself, so applications that use it have access\nto it.\n\n >>> os.remove(storage.before_from_file)\n\n >>> os.path.exists(before_file)\n False\n\nIf we restart the storage again, a new file will be created.\n\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %%import zc.beforestorage\n ...\n ... \n ... before-from-file %s\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\" % before_file)\n\n >>> storage\n \n\n >>> storage.close()\n\nNote that unlike the \"before\" option, the \"before-from-file\" file cannot\ncontain special values such as \"now\" or \"startup\".\n\n >>> f = open(before_file, 'w')\n >>> _ = f.write('now')\n >>> f.close()\n\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %%import zc.beforestorage\n ...\n ... \n ... before-from-file %s\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\" % before_file)\n Traceback (most recent call last):\n ...\n ValueError: 8-byte array expected\n\nNote that only one of \"before\" or \"before-from-file\" options can be specified,\nnot both:\n\n >>> storage = ZODB.config.storageFromString(\"\"\"\n ...\n ... %%import zc.beforestorage\n ...\n ... \n ... before 2008-01-01\n ... before-from-file %s\n ... \n ... path my.fs\n ... \n ... \n ... \"\"\" % before_file)\n Traceback (most recent call last):\n ...\n ValueError: Only one of \"before\" or \"before-from-file\" options can be specified, not both\n\n\nCleanup...\n\n >>> import shutil\n >>> shutil.rmtree(tempdir)\n\n >>> zc.beforestorage.get_utcnow = orig_get_utcnow\n\n\nDemonstration (doctest)\n=======================\n\nNote that most people will configure the storage through ZConfig. If\nyou are one of those people, you may want to stop here. :) The\nexamples below show you how to use the storage from Python, but they\nalso exercise lots of details you might not be interested in.\n\nTo see how this works at the Python level, we'll create a file\nstorage, and use a before storage to provide views on it.\n\n >>> import ZODB.FileStorage\n >>> fs = ZODB.FileStorage.FileStorage('Data.fs')\n >>> from ZODB.DB import DB\n >>> db = DB(fs)\n >>> conn = db.open()\n >>> root = conn.root()\n >>> import persistent.mapping\n\nWe'll record transaction identifiers, which we'll use to when opening\nthe before storage.\n\n >>> import transaction\n >>> transactions = [root._p_serial]\n >>> for i in range(1, 11):\n ... root[i] = persistent.mapping.PersistentMapping()\n ... transaction.get().note(\"trans %s\" % i)\n ... transaction.commit()\n ... transactions.append(root._p_serial)\n\nWe create a before storage by calling the Before constructer\nwith an existing storage and a timestamp:\n\n >>> import zc.beforestorage\n >>> b5 = zc.beforestorage.Before(fs, transactions[5])\n >>> db5 = DB(b5)\n >>> conn5 = db5.open()\n >>> root5 = conn5.root()\n >>> len(root5)\n 4\n\nhere we see the database as it was before the 5th transaction was\ncommitted. If we try to access a later object, we'll get a\nPOSKeyError:\n\n >>> conn5.get(root[5]._p_oid)\n Traceback (most recent call last):\n ...\n POSKeyError: 0x05\n\nSimilarly, while we can access earlier object revisions, we can't\naccess revisions at the before time or later:\n\n >>> _ = b5.loadSerial(root._p_oid, transactions[2])\n\n >>> b5.loadSerial(root._p_oid, transactions[5])\n Traceback (most recent call last):\n ...\n POSKeyError: 0x00\n\n >>> conn5.get(root[5]._p_oid)\n Traceback (most recent call last):\n ...\n POSKeyError: 0x05\n\nLet's run through the storage methods:\n\n >>> (b5.getName() ==\n ... 'Data.fs before %s' % ZODB.TimeStamp.TimeStamp(transactions[5]))\n True\n\n >>> b5.getSize() == fs.getSize()\n True\n\n >>> for hd in b5.history(root._p_oid, size=3):\n ... print(hd['description'].decode('utf-8'))\n trans 4\n trans 3\n trans 2\n\n >>> b5.isReadOnly()\n True\n\n >>> transactions[4] <= b5.lastTransaction() < transactions[5]\n True\n\n >>> len(b5) == len(fs)\n True\n\n >>> p, s1, s2 = b5.loadBefore(root._p_oid, transactions[5])\n >>> p == fs.loadSerial(root._p_oid, transactions[4])\n True\n >>> s1 == transactions[4]\n True\n >>> s2 is None\n True\n\n >>> p, s1, s2 = b5.loadBefore(root._p_oid, transactions[4])\n >>> p == fs.loadSerial(root._p_oid, transactions[3])\n True\n >>> s1 == transactions[3]\n True\n >>> s2 == transactions[4]\n True\n\n >>> b5.getTid(root._p_oid) == transactions[4]\n True\n\n >>> b5.tpc_transaction()\n\n >>> try:\n ... b5.new_oid()\n ... except Exception as e: # Workaround http://bugs.python.org/issue19138\n ... print(e.__class__.__name__)\n ReadOnlyError\n\n >>> from ZODB.TimeStamp import TimeStamp\n >>> try:\n ... b5.pack(TimeStamp(transactions[3]).timeTime(), lambda p: [])\n ... except Exception as e:\n ... print(e.__class__.__name__)\n ReadOnlyError\n\n >>> b5.registerDB(db5)\n\n >>> b5.sortKey() == fs.sortKey()\n True\n\n >>> try:\n ... b5.tpc_begin(transaction.get())\n ... except Exception as e:\n ... print(e.__class__.__name__)\n ReadOnlyError\n\n >>> b5.store(root._p_oid, transactions[4], b5.load(root._p_oid)[0], '',\n ... transaction.get())\n ... # doctest: +ELLIPSIS\n Traceback (most recent call last):\n ...\n StorageTransactionError: ...\n\n >>> b5.tpc_vote(transaction.get())\n ... # doctest: +ELLIPSIS\n Traceback (most recent call last):\n ...\n ZODB.POSException.StorageTransactionError: ...\n\n >>> b5.tpc_finish(transaction)\n ... # doctest: +ELLIPSIS\n Traceback (most recent call last):\n ...\n ZODB.POSException.StorageTransactionError: ...\n\n >>> b5.tpc_transaction()\n >>> b5.tpc_abort(transaction)\n\nBefore storages don't support undo:\n\n >>> b5.supportsUndo\n Traceback (most recent call last):\n ...\n AttributeError: 'Before' object has no attribute 'supportsUndo'\n\n(Don't even ask about versions. :)\n\nClosing a before storage closes the underlying storage:\n\n >>> b5.close()\n >>> fs.load(root._p_oid, '') # doctest: +ELLIPSIS\n Traceback (most recent call last):\n ...\n ValueError: ...\n\nIf we ommit a timestamp when creating a before storage, the current\ntime will be used:\n\n >>> fs = ZODB.FileStorage.FileStorage('Data.fs')\n >>> from ZODB.DB import DB\n >>> db = DB(fs)\n >>> conn = db.open()\n >>> root = conn.root()\n\n >>> bnow = zc.beforestorage.Before(fs)\n >>> dbnow = DB(bnow)\n >>> connnow = dbnow.open()\n >>> rootnow = connnow.root()\n\n >>> for i in range(1, 11):\n ... root[i] = persistent.mapping.PersistentMapping()\n ... transaction.get().note(\"trans %s\" % i)\n ... transaction.commit()\n ... transactions.append(root._p_serial)\n\n >>> len(rootnow)\n 10\n\n >>> dbnow.close()\n\nThe timestamp may be passed directory, or as an ISO time. For\nexample:\n\n >>> fs = ZODB.FileStorage.FileStorage('Data.fs')\n >>> iso = 'T'.join(str(ZODB.TimeStamp.TimeStamp(transactions[5])).split()\n ... )[:19]\n >>> b5 = zc.beforestorage.Before(fs, iso)\n >>> db5 = DB(b5)\n >>> conn5 = db5.open()\n >>> root5 = conn5.root()\n >>> len(root5)\n 4\n\n >>> b5.close()\n\nBlob Support\n------------\n\nBefore storage supports blobs if the storage it wraps supports blobs,\nand, in fact, it simply exposes the underlying storages loadBlob and\ntemporaryDirectory methods.\n\n >>> fs = ZODB.FileStorage.FileStorage('Data.fs')\n >>> import ZODB.blob\n >>> bs = ZODB.blob.BlobStorage('blobs', fs)\n >>> db = ZODB.DB(bs)\n >>> conn = db.open()\n >>> conn.root()['blob'] = ZODB.blob.Blob()\n >>> _ = conn.root()['blob'].open('w').write(b'data1')\n >>> transaction.commit()\n\n >>> bnow = zc.beforestorage.Before(bs)\n >>> dbnow = DB(bnow)\n >>> connnow = dbnow.open()\n >>> rootnow = connnow.root()\n\n >>> _ = conn.root()['blob'].open('w').write(b'data2')\n >>> transaction.commit()\n\n >>> print(rootnow['blob'].open().read().decode('utf-8'))\n data1\n\n >>> bnow.temporaryDirectory() == bs.temporaryDirectory()\n True\n\n >>> import ZODB.interfaces, zope.interface.verify\n >>> zope.interface.verify.verifyObject(\n ... ZODB.interfaces.IBlobStorage, bnow)\n True\n\n >>> bnow.close()\n\nDownload\n========",
"description_content_type": null,
"docs_url": null,
"download_url": "UNKNOWN",
"downloads": {
"last_day": -1,
"last_month": -1,
"last_week": -1
},
"home_page": "UNKNOWN",
"keywords": null,
"license": "ZPL 2.1",
"maintainer": null,
"maintainer_email": null,
"name": "zc.beforestorage",
"package_url": "https://pypi.org/project/zc.beforestorage/",
"platform": "UNKNOWN",
"project_url": "https://pypi.org/project/zc.beforestorage/",
"project_urls": {
"Download": "UNKNOWN",
"Homepage": "UNKNOWN"
},
"release_url": "https://pypi.org/project/zc.beforestorage/0.5.1/",
"requires_dist": null,
"requires_python": null,
"summary": "View storage before a given time",
"version": "0.5.1"
},
"last_serial": 903150,
"releases": {
"0.1.0": [
{
"comment_text": "",
"digests": {
"md5": "a41d2e63d6320c503d61163a6ce659b2",
"sha256": "fff59d00bcbec79c4046ddd97d96606743d6db101d9867c4977779d8657de2ea"
},
"downloads": -1,
"filename": "zc.beforestorage-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "a41d2e63d6320c503d61163a6ce659b2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 7869,
"upload_time": "2008-02-04T17:45:51",
"url": "https://files.pythonhosted.org/packages/45/13/5ef746c848aec347c49df38802cb5bba13c7283af8eb8b29212218c9f60b/zc.beforestorage-0.1.0.tar.gz"
}
],
"0.1.1": [
{
"comment_text": "",
"digests": {
"md5": "55e60080a3bdfe0f97d157359659f371",
"sha256": "745bb8bf4f9485fdfd3e6958605397a656c0f5f7bd898a79ab7b14da9d45ca93"
},
"downloads": -1,
"filename": "zc.beforestorage-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "55e60080a3bdfe0f97d157359659f371",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8636,
"upload_time": "2008-02-07T18:13:57",
"url": "https://files.pythonhosted.org/packages/cf/0c/631a6ab6e35be44c4fc9fc39ccab40582fe401a2fedf536b2d0e34dc7236/zc.beforestorage-0.1.1.tar.gz"
}
],
"0.2.0": [
{
"comment_text": "",
"digests": {
"md5": "67fa3fc8a56cc6cb904f83ed215525a9",
"sha256": "7dd1e18ec7e028b6bb26a42b70a393920bad320870d6f27b8f6cda53479f8a4b"
},
"downloads": -1,
"filename": "zc.beforestorage-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "67fa3fc8a56cc6cb904f83ed215525a9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8428,
"upload_time": "2008-03-05T19:13:02",
"url": "https://files.pythonhosted.org/packages/56/f2/6c6df1dc0c82c319df57d11c5bd46ed5be28090f493e073dabf2f6a4e879/zc.beforestorage-0.2.0.tar.gz"
}
],
"0.3.0": [
{
"comment_text": "",
"digests": {
"md5": "6dc23d35bf2e5d89a2242856d4370c65",
"sha256": "940a61104e66653e9266d43fa46287817ab39a5c80c15e988c722d833517f284"
},
"downloads": -1,
"filename": "zc.beforestorage-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "6dc23d35bf2e5d89a2242856d4370c65",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8166,
"upload_time": "2008-12-01T18:02:52",
"url": "https://files.pythonhosted.org/packages/20/fe/21f05d45e94438fb2ecee4cc8e1d6aa9e1c66d37d29e5eb8aadc6eb42c75/zc.beforestorage-0.3.0.tar.gz"
}
],
"0.3.1": [
{
"comment_text": "",
"digests": {
"md5": "3d0271ed15e418e0b4cb54a28bed19e2",
"sha256": "fb8a286210fc416ed189817b5a773e9f31b7582e2b5e9ebac9b0433cdeff8456"
},
"downloads": -1,
"filename": "zc.beforestorage-0.3.1.tar.gz",
"has_sig": false,
"md5_digest": "3d0271ed15e418e0b4cb54a28bed19e2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8221,
"upload_time": "2008-12-01T18:29:01",
"url": "https://files.pythonhosted.org/packages/24/ff/956b7438a8b561aefcd9c2ebe1e6321f9c042a936cd5b2ceb43f5b9ed938/zc.beforestorage-0.3.1.tar.gz"
}
],
"0.3.2": [
{
"comment_text": "",
"digests": {
"md5": "7813167e74b1712643369a84612025ba",
"sha256": "0b9b148854b136c0c37a4354071831b873d651c42a3a30a64342de9e0d898a21"
},
"downloads": -1,
"filename": "zc.beforestorage-0.3.2.tar.gz",
"has_sig": false,
"md5_digest": "7813167e74b1712643369a84612025ba",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 8678,
"upload_time": "2008-12-05T15:07:46",
"url": "https://files.pythonhosted.org/packages/86/f0/0c5cc11b954020081168137b9ebfaec527920a6079b899bd7a13b82f0c91/zc.beforestorage-0.3.2.tar.gz"
}
],
"0.4.0": [
{
"comment_text": "",
"digests": {
"md5": "2832ad5c4dbfaf88ef3dbe0dee9242c3",
"sha256": "424b66b2f0e18b432a97bc0b6f058a9f11874c5d4aa8701ebe7da46490a93611"
},
"downloads": -1,
"filename": "zc.beforestorage-0.4.0.tar.gz",
"has_sig": false,
"md5_digest": "2832ad5c4dbfaf88ef3dbe0dee9242c3",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 12038,
"upload_time": "2010-12-09T23:25:52",
"url": "https://files.pythonhosted.org/packages/18/c2/e7107550ffb08f74c438c1aa33eef552bdd45f7d2947171e6d78cd3ebe9e/zc.beforestorage-0.4.0.tar.gz"
}
],
"0.5.0": [
{
"comment_text": "",
"digests": {
"md5": "0b5d57793a6e4167217b3188ecc8d447",
"sha256": "b2a437ac1e6b125b82d2d9983ad5187b9613b7c30092c59cb9eddb6a09bf6a93"
},
"downloads": -1,
"filename": "zc.beforestorage-0.5.0.tar.gz",
"has_sig": false,
"md5_digest": "0b5d57793a6e4167217b3188ecc8d447",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 12053,
"upload_time": "2013-10-25T13:44:59",
"url": "https://files.pythonhosted.org/packages/d6/bb/284926853ba64d413a6c2cfdd5f4ea401702151207328e065946f98ee865/zc.beforestorage-0.5.0.tar.gz"
}
],
"0.5.1": [
{
"comment_text": "",
"digests": {
"md5": "8d6ce18dd18cffbc59631807c9602a69",
"sha256": "3d2529da826ce9845110db3d1e9c22b4f8df6662392f4a6bb27dd726b6defc88"
},
"downloads": -1,
"filename": "zc.beforestorage-0.5.1.tar.gz",
"has_sig": false,
"md5_digest": "8d6ce18dd18cffbc59631807c9602a69",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 14951,
"upload_time": "2013-10-25T13:51:23",
"url": "https://files.pythonhosted.org/packages/07/7b/38517cacb5bfa060c709f70004522dd0acbf67acde2895ffab483f831b0c/zc.beforestorage-0.5.1.tar.gz"
}
]
},
"urls": [
{
"comment_text": "",
"digests": {
"md5": "8d6ce18dd18cffbc59631807c9602a69",
"sha256": "3d2529da826ce9845110db3d1e9c22b4f8df6662392f4a6bb27dd726b6defc88"
},
"downloads": -1,
"filename": "zc.beforestorage-0.5.1.tar.gz",
"has_sig": false,
"md5_digest": "8d6ce18dd18cffbc59631807c9602a69",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 14951,
"upload_time": "2013-10-25T13:51:23",
"url": "https://files.pythonhosted.org/packages/07/7b/38517cacb5bfa060c709f70004522dd0acbf67acde2895ffab483f831b0c/zc.beforestorage-0.5.1.tar.gz"
}
]
}