{ "info": { "author": "gocept gmbh & co. kg", "author_email": "mail@gocept.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: Zope3", "Framework :: Zope :: 3", "Intended Audience :: Developers", "License :: OSI Approved", "License :: OSI Approved :: Zope Public License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 2 :: Only", "Topic :: Software Development" ], "description": "gocept.runner\n=============\n\nCreate stand alone programs with full a Zope3 runtime environment.\nThese programs can be used either as one time run scripts or can be\nautomatically called after a defined period of time.\n\n.. contents::\n\n\nCreating runners\n================\n\nThe ``gocept.runner`` package allows it to *easily* create small, long running\nscripts which interact with the ZODB. The scripts have the full component\narchitecture set up when they're run.\n\nRunners are defined with the appmain decorator:\n\n>>> import logging\n>>> import gocept.runner\n>>> work_count = 0\n>>> @gocept.runner.appmain(ticks=0.1)\n... def worker():\n... import zope.app.appsetup.product\n... log = logging.getLogger('test')\n... log.info(\"Working\")\n... log.info(sorted(\n... zope.app.appsetup.product.getProductConfiguration('test').items()))\n... global work_count\n... work_count += 1\n... if work_count >= 3:\n... return gocept.runner.Exit\n\n\nThe decorated worker takes two arguments now:\n\n1. The name of an object in the root which will be set as site or None for the\n root.\n2. The path to a configuration file (zope.conf)\n\nCreate a simple zope.conf:\n\n>>> import os.path\n>>> import tempfile\n>>> zodb_path = tempfile.mkdtemp()\n>>> site_zcml = os.path.join(\n... os.path.dirname(__file__), 'ftesting.zcml')\n>>> fd, zope_conf = tempfile.mkstemp()\n>>> zope_conf_file = os.fdopen(fd, 'w')\n>>> zope_conf_file.write('''\\\n... site-definition %s\n... \n... \n... path %s/Data.fs\n... \n... \n... \n... foo bar\n... test-principal zope.mgr\n... \n... \n... \n... formatter zope.exceptions.log.Formatter\n... path STDOUT\n... \n... \n... ''' % (site_zcml, zodb_path))\n>>> zope_conf_file.close()\n\n\nSo call the worker:\n\n>>> worker(None, zope_conf)\n------\n... INFO test Working\n------\n... INFO test [('foo', 'bar'), ('test-principal', 'zope.mgr')]\n------\n... INFO test Working\n------\n... INFO test [('foo', 'bar'), ('test-principal', 'zope.mgr')]\n------\n... INFO test Working\n------\n... INFO test [('foo', 'bar'), ('test-principal', 'zope.mgr')]\n\n\n\nSignals\n-------\n\nThe worker-procss can be terminated by SIGTERM and SIGHUP in a sane way. Write\na script to a temporary file:\n\n>>> import sys\n>>> runner_path = os.path.abspath(\n... os.path.join(os.path.dirname(__file__), '..', '..'))\n>>> fd, script_name = tempfile.mkstemp(suffix='.py')\n>>> exchange_fd, exchange_file_name = tempfile.mkstemp()\n>>> script = os.fdopen(fd, 'w')\n>>> script.write(\"\"\"\\\n... import sys\n... sys.path[0:0] = %s\n... sys.path.insert(0, '%s')\n... import gocept.runner\n...\n... f = open('%s', 'w')\n...\n... @gocept.runner.appmain(ticks=0.1)\n... def worker():\n... f.write(\"Working.\\\\n\")\n... f.flush()\n...\n... worker(None, '%s')\n... \"\"\" % (sys.path, runner_path, exchange_file_name, zope_conf))\n>>> script.close()\n\n\nCall the script and wait for it to produce some output:\n\n>>> import signal\n>>> import subprocess\n>>> import time\n>>> exchange = os.fdopen(exchange_fd, 'r+')\n>>> proc = subprocess.Popen(\n... [sys.executable, script_name],\n... stdout=subprocess.PIPE)\n>>> while not exchange.read():\n... time.sleep(0.1)\n... exchange.seek(0, 0)\n>>> exchange.seek(0, 0)\n>>> print exchange.read(),\nWorking.\n\nOkay, now kill it:\n\n>>> os.kill(proc.pid, signal.SIGTERM)\n\nWait for the process to really finish and get the output. The runner logs that\nit was terminated:\n\n>>> stdout, stderr = proc.communicate()\n>>> print stdout,\n------\n... INFO gocept.runner.runner Received signal 15, terminating.\n\n\nThis also works with SIGHUP:\n\n>>> exchange.truncate(0)\n>>> proc = subprocess.Popen(\n... [sys.executable, script_name],\n... stdout=subprocess.PIPE)\n>>> while not exchange.read():\n... time.sleep(0.1)\n... exchange.seek(0, 0)\n>>> exchange.seek(0, 0)\n>>> print exchange.read(),\nWorking.\n\nOkay, now kill it:\n\n>>> os.kill(proc.pid, signal.SIGHUP)\n>>> stdout, stderr = proc.communicate()\n>>> print stdout,\n------\n... INFO gocept.runner.runner Received signal 1, terminating.\n\n\nClean up:\n\n>>> os.remove(script_name)\n>>> os.remove(exchange_file_name)\n\n\nSetting the principal\n---------------------\n\nIt is also prossible to create a main loop which runs in an interaction:\n\n>>> def get_principal():\n... return 'zope.mgr'\n\n>>> import zope.security.management\n>>> work_count = 0\n>>> def interaction_worker():\n... global work_count\n... work_count += 1\n... if work_count >= 3:\n... raise SystemExit(1)\n... log = logging.getLogger('test')\n... interaction = zope.security.management.getInteraction()\n... principal = interaction.participations[0].principal\n... log.info(\"Working as %s\" % principal.id)\n>>> worker = gocept.runner.appmain(ticks=0.1, principal=get_principal)(\n... interaction_worker)\n\nCall the worker now:\n\n>>> worker(None, zope_conf)\n------\n... INFO test Working as zope.mgr\n------\n... INFO test Working as zope.mgr\n\n\nAfter the worker is run there is no interaction:\n\n>>> zope.security.management.queryInteraction() is None\nTrue\n\nIt's quite common to read the principal from zope.conf. Therefore there is a\nhelper which makes this task easier:\n\n>>> work_count = 0\n>>> worker = gocept.runner.appmain(\n... ticks=0.1,\n... principal=gocept.runner.from_config('test', 'test-principal'))(\n... interaction_worker)\n>>> worker(None, zope_conf)\n------\n... INFO test Working as zope.mgr\n------\n... INFO test Working as zope.mgr\n\n\nSubsites\n--------\n\nIt is possible to directly work on sites inside the root. The site must already\nexist of course, otherwise there will be an error:\n\n>>> worker('a-site', zope_conf)\nTraceback (most recent call last):\n ...\nKeyError: 'a-site'\n\n\nClean up:\n\n>>> import shutil\n>>> shutil.rmtree(zodb_path)\n>>> os.remove(zope_conf)\n\n\nRun once commands\n=================\n\nIt is often needed to run a command once (or via cron) with the full component\narchitecture. Usually ``zopectl run`` is used for this.\n\n>>> import logging\n>>> import gocept.runner\n>>> import zope.component.hooks\n>>> @gocept.runner.once()\n... def worker():\n... log = logging.getLogger('test')\n... log.info(\"Working.\")\n... site = zope.component.hooks.getSite()\n... if hasattr(site, 'store'):\n... log.info(\"Having attribute store.\")\n... site.store = True\n\n\nDefine a Zope environment:\n\n>>> import os.path\n>>> import tempfile\n>>> zodb_path = tempfile.mkdtemp()\n>>> site_zcml = os.path.join(\n... os.path.dirname(__file__), 'ftesting.zcml')\n>>> fd, zope_conf = tempfile.mkstemp()\n>>> zope_conf_file = os.fdopen(fd, 'w')\n>>> zope_conf_file.write('''\\\n... site-definition %s\n... \n... \n... path %s/Data.fs\n... \n... \n... \n... foo bar\n... \n... \n... \n... formatter zope.exceptions.log.Formatter\n... path STDOUT\n... \n... \n... ''' % (site_zcml, zodb_path))\n>>> zope_conf_file.close()\n\n\nSo call the worker for the first time. It will be terminated after one call:\n\n>>> worker(None, zope_conf)\n------\n... INFO test Working.\n\n\nCalling it a second time indicates that a property was changed in the first\nrun:\n\n>>> worker(None, zope_conf)\n------\n... INFO test Working.\n------\n... INFO test Having attribute store.\n...\n\n\nRunner details\n==============\n\nMain loop\n---------\n\nThe main loop loops until it encounters a KeyboardInterrupt or a SystemExit\nexception and calls the worker once a second.\n\nDefine a worker function which exits when it is called the 3rd time:\n\n>>> work_count = 0\n>>> def worker():\n... print \"Working\"\n... global work_count\n... work_count += 1\n... if work_count >= 3:\n... raise SystemExit(1)\n\n\nCall the main loop:\n\n>>> import gocept.runner.runner\n>>> gocept.runner.runner.MainLoop(getRootFolder(), 0.1, worker)()\nWorking\nWorking\nWorking\n>>> work_count\n3\n\n\nDuring the loop the site is set:\n\n>>> import zope.component.hooks\n>>> zope.component.hooks.getSite() is None\nTrue\n>>> def worker():\n... print zope.component.hooks.getSite()\n... raise SystemExit(1)\n>>> gocept.runner.runner.MainLoop(getRootFolder(), 0.1, worker)()\n\n\n\n\nAfter the loop, no site is set again:\n\n>>> zope.component.hooks.getSite() is None\nTrue\n\n\nWhen the worker passes without error a transaction is committed:\n\n>>> work_count = 0\n>>> def worker():\n... print \"Working\"\n... global work_count\n... work_count += 1\n... if work_count >= 2:\n... raise SystemExit(1)\n... site = zope.component.hooks.getSite()\n... site.worker_done = 1\n>>> gocept.runner.runner.MainLoop(getRootFolder(), 0.1, worker)()\nWorking\nWorking\n\nWe have set the attribute ``worker_done`` now:\n\n>>> getRootFolder().worker_done\n1\n\n\nWhen the worker produces an error, the transaction is aborted:\n\n>>> work_count = 0\n>>> def worker():\n... global work_count\n... work_count += 1\n... print \"Working\"\n... site = zope.component.hooks.getSite()\n... site.worker_done += 1\n... if work_count < 3:\n... raise ValueError('hurz')\n... raise SystemExit(1)\n>>> gocept.runner.runner.MainLoop(getRootFolder(), 0.1, worker)()\nWorking\nWorking\nWorking\n\n\nWe still have the attribute ``worker_done`` set to 1:b\n\n>>> getRootFolder().worker_done\n1\n\n\nControlling sleep time\n----------------------\n\nThe worker function can control the sleep time.\n\nRegister a log handler so we can observe this:\n\n>>> import logging\n>>> import StringIO\n>>> log = StringIO.StringIO()\n>>> log_handler = logging.StreamHandler(log)\n>>> logging.root.addHandler(log_handler)\n>>> old_log_level = logging.root.level\n>>> logging.root.setLevel(logging.DEBUG)\n\n\n>>> work_count = 0\n>>> def worker():\n... global work_count\n... work_count += 1\n... new_sleep = work_count * 0.1\n... if work_count == 3:\n... print \"Will sleep default\"\n... return None\n... if work_count > 3:\n... raise SystemExit(1)\n... print \"Will sleep\", new_sleep\n... return new_sleep\n>>> gocept.runner.runner.MainLoop(getRootFolder(), 0.15, worker)()\nWill sleep 0.1\nWill sleep 0.2\nWill sleep default\n\nThe real sleep values are in the log:\n\n>>> print log.getvalue(),\nnew transaction\ncommit\nSleeping 0.1 seconds\nnew transaction\ncommit\nSleeping 0.2 seconds\nnew transaction\ncommit\nSleeping 0.15 seconds\nnew transaction\nabort\n\nWhen an error occours within the worker, the default sleep time will be used:\n\n>>> log.seek(0)\n>>> log.truncate()\n>>> work_count = 0\n>>> def worker():\n... global work_count\n... work_count += 1\n... if work_count == 1:\n... new_sleep = 0.1\n... elif work_count == 2:\n... print \"Failing\"\n... raise Exception(u\"F\\xfcil!\")\n... elif work_count == 3:\n... print \"Will sleep default\"\n... return None\n... elif work_count > 3:\n... return gocept.runner.Exit\n... print \"Will sleep\", new_sleep\n... return new_sleep\n>>> gocept.runner.runner.MainLoop(getRootFolder(), 0.15, worker)()\nWill sleep 0.1\nFailing\nWill sleep default\n\nThe real sleep values are in the log:\n\n>>> print log.getvalue(),\nnew transaction\ncommit\nSleeping 0.1 seconds\nnew transaction\nError in worker: Exception(u'F\\xfcil!',)\nTraceback (most recent call last):\n ...\nException: F\\xfcil!\nabort\nSleeping 0.15 seconds\nnew transaction\ncommit\nSleeping 0.15 seconds\nnew transaction\ncommit\n\nRestore old log handler:\n\n>>> logging.root.removeHandler(log_handler)\n>>> logging.root.setLevel(old_log_level)\n\n\nMultiple commit helper\n======================\n\n\nSometimes you have several actions and want to commit in between each step.\n``gocept.runner`` provides a decorator ``transaction_per_item`` that simplifies\nwriting this down, for example::\n\n @gocept.runner.transaction_per_item\n def multiple_steps():\n for item in source:\n yield lambda: process(item)\n\nThis will call each ``process(item)`` in turn and commit after each. If an\nexception is raised by a step, the transaction is aborted and the loop\ncontinues with the next step. ZODB ConflictErrors are ignored likewise.\n\n\nChanges\n=======\n\n2.0 (2018-03-14)\n----------------\n\n- Backwards incompatible change: No longer depend on ``zope.app.server``,\n and no longer superfluously use its `ZConfig` schema, which superfluously\n requires an `` section that does not make any sense in our context\n anyway. So `` is no longer allowed in the ZConfing config file\n used by this package.\n\n\n1.0 (2016-01-12)\n----------------\n\n- No longer depend on ``zope.app.component``.\n\n\n0.7.1 (2015-01-28)\n------------------\n\n- Fix faulty release 0.7.0.\n\n\n0.7.0 (2015-01-28)\n------------------\n\n- An error message is correctly logged when the worker produces an exception\n which cannot be represented in us-ascii. This used to cause an exception in\n the logging module. The cause of those exceptions where quite hard to track.\n\n- Removed dependency on zope.app.security which was neither declared nor\n necessary.\n\n- Moved project home to .\n\n\n0.6.0 (2011-12-01)\n------------------\n\n- Added transaction_per_item decorator.\n- Use stdlib's doctest instead of zope.testing.\n\n\n0.5.3 (2010-04-14)\n------------------\n\n- Use log.error/log.warning instead of log.exception. Conflict errors are\n logged as warning now, because they are not really a problem.\n\n0.5.2 (2010-04-14)\n------------------\n\n- Convert logged exceptions to str.\n\n\n0.5.1 (2009-10-13)\n------------------\n\n- Declared dependencies correctly.\n\n\n0.5 (2009-09-21)\n++++++++++++++++\n\n- Does no longer use ``zope.app.twisted`` but ``zope.app.server`` instead.\n\n\n0.4 (2009-09-03)\n++++++++++++++++\n\n- The principal set by appmain/once can be computed by a function now.\n\n0.3.2 (2009-05-21)\n------------------\n\n- Fixed handling of subsites in appmain.\n\n0.3.1 (2009-05-21)\n------------------\n\n- Declared namespace package.\n\n0.3 (2009-04-15)\n++++++++++++++++\n\n- When a worker fails the default sleep time (instead of the last one) will be\n used.\n\n0.2 (2009-04-09)\n++++++++++++++++\n\n- Added a clean way to exit the runner (by returning gocept.runner.Exit).\n\n0.1 (2009-04-07)\n++++++++++++++++\n\n- first public release", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://bitbucket.org/gocept/gocept.runner/", "keywords": "zope3 mainloop", "license": "ZPL 2.1", "maintainer": "", "maintainer_email": "", "name": "gocept.runner", "package_url": "https://pypi.org/project/gocept.runner/", "platform": "", "project_url": "https://pypi.org/project/gocept.runner/", "project_urls": { "Homepage": "https://bitbucket.org/gocept/gocept.runner/" }, "release_url": "https://pypi.org/project/gocept.runner/2.0/", "requires_dist": null, "requires_python": "", "summary": "Create stand alone programs with full Zope3 runtime environment", "version": "2.0" }, "last_serial": 3667822, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "84a4697d88dec9a3adb473e0e6685732", "sha256": "a607f66fa9364a5ea16c37238fad8f402ac67d7446db1a5f8bf1f88219779135" }, "downloads": -1, "filename": "gocept.runner-0.1.tar.gz", "has_sig": false, "md5_digest": "84a4697d88dec9a3adb473e0e6685732", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10957, "upload_time": "2009-04-07T22:03:45", "url": "https://files.pythonhosted.org/packages/a2/ca/78a5df4c2f01dc1299c95da1aadeec31c8976bdb9526f1f064b69e441528/gocept.runner-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "dce7f946e3f3154b95ecc438bb96edd0", "sha256": "d2a17e9233f78b583cfba4dd53aa32ecfadcf4c44ba7a757ab4c13d57e022d76" }, "downloads": -1, "filename": "gocept.runner-0.2.tar.gz", "has_sig": false, "md5_digest": "dce7f946e3f3154b95ecc438bb96edd0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11080, "upload_time": "2009-04-09T10:29:23", "url": "https://files.pythonhosted.org/packages/1d/19/e9c264078f28cee1d9bf4dae143aa053afd1da51693c263ac3687993125f/gocept.runner-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "23f226bc3f22cd1c38d15ba0ea3dd71a", "sha256": "570e4d6780be95b03f26277f9c1c3d336e3206c2466ac18146a0226eaa030a11" }, "downloads": -1, "filename": "gocept.runner-0.3.tar.gz", "has_sig": false, "md5_digest": "23f226bc3f22cd1c38d15ba0ea3dd71a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11552, "upload_time": "2009-04-15T08:57:26", "url": "https://files.pythonhosted.org/packages/b5/91/783a715debc98ed142581a78aabb56bd56f3b47bf1d6d333d9c1099ccaa2/gocept.runner-0.3.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "24d0ca42e8e54e0eb600d11350e28b33", "sha256": "de4c3ca36b90a4d9b881b2b0499e6b00c91f1d8d7bfabee794a24886819266ce" }, "downloads": -1, "filename": "gocept.runner-0.3.1.tar.gz", "has_sig": false, "md5_digest": "24d0ca42e8e54e0eb600d11350e28b33", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11722, "upload_time": "2009-05-21T09:23:57", "url": "https://files.pythonhosted.org/packages/d1/23/96d0a71a2ee5915ebf3e60ea7e2944665ab78d581e2c546f11a0e7604850/gocept.runner-0.3.1.tar.gz" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "5b802107bae4f2d85a6383b3b22aedbb", "sha256": "ae6622dbd24b7607b8199bef8f082ebd767eafbf9525de0feb043f56f15f2ff7" }, "downloads": -1, "filename": "gocept.runner-0.3.2.tar.gz", "has_sig": false, "md5_digest": "5b802107bae4f2d85a6383b3b22aedbb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11917, "upload_time": "2009-05-21T10:43:31", "url": "https://files.pythonhosted.org/packages/5f/8e/7ca32ae71ea0085819c1dec28bd252051dcf5dd9dcc6200093bde845c691/gocept.runner-0.3.2.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "a43772014f5cf9a9644f3e1038c01e23", "sha256": "ebc528cfd9d7d5112fa75fb0a5e47f271ebc135723de035eff5774d6f82e0519" }, "downloads": -1, "filename": "gocept.runner-0.4.tar.gz", "has_sig": false, "md5_digest": "a43772014f5cf9a9644f3e1038c01e23", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10947, "upload_time": "2009-09-03T19:11:56", "url": "https://files.pythonhosted.org/packages/70/dc/5711f5e45506bee2ceda602f9a56db43f707f4960a0537c781e9264d1f9d/gocept.runner-0.4.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "455bc3f33b9ead35fd3dc7c30ba1f5b8", "sha256": "db092872987849d09e75108cf9d03bcd5581324c897f4c36ee5370e9abf457f6" }, "downloads": -1, "filename": "gocept.runner-0.5.tar.gz", "has_sig": false, "md5_digest": "455bc3f33b9ead35fd3dc7c30ba1f5b8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10985, "upload_time": "2009-09-21T11:10:20", "url": "https://files.pythonhosted.org/packages/68/d4/06ef6c690f9e2ce46b301cf8f220282b84948bf713a5a3dc754ae9d066e1/gocept.runner-0.5.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "1169c549f5716800d394faa7869cf0a0", "sha256": "2ded3eba4ebd2b30994f13be0ee1435f78e0df50b5051b2fd2e54abdcc33cc6a" }, "downloads": -1, "filename": "gocept.runner-0.5.1.tar.gz", "has_sig": false, "md5_digest": "1169c549f5716800d394faa7869cf0a0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11104, "upload_time": "2009-10-13T10:44:02", "url": "https://files.pythonhosted.org/packages/45/bd/efb6d3ebb75b79dccdf681794b28ce949e5eb80bdab5c4c79d176f60caa0/gocept.runner-0.5.1.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "c04376b2066dc4b199984a9de92b5133", "sha256": "aa5cbe2340e5622e4a9694d70e0fcc40d63f955ee05c184b012249514d73865d" }, "downloads": -1, "filename": "gocept.runner-0.5.2.tar.gz", "has_sig": false, "md5_digest": "c04376b2066dc4b199984a9de92b5133", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11257, "upload_time": "2010-04-14T14:43:20", "url": "https://files.pythonhosted.org/packages/23/ac/3c4f94d4d2b1c0754c3dcc80b4b57e7ef189e4dccdfd7cd1b715956b91f2/gocept.runner-0.5.2.tar.gz" } ], "0.5.3": [ { "comment_text": "", "digests": { "md5": "c3756b493488560241964d02a63c48fc", "sha256": "7bbe94b6cbc7d5e96f0166b041d7d2f2db9297f64389b80fef0e2c36e23af12e" }, "downloads": -1, "filename": "gocept.runner-0.5.3.tar.gz", "has_sig": false, "md5_digest": "c3756b493488560241964d02a63c48fc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11314, "upload_time": "2010-04-14T16:02:53", "url": "https://files.pythonhosted.org/packages/a7/84/dfd503e95d2e140ab1758a6972f6216a76dcb0005d06046e03d12dd05cf9/gocept.runner-0.5.3.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "79ddeb16746be890c0c6c0d325252d3b", "sha256": "f4a27ba3e12d3204a2919550b95b3cc7c8bcac010865087dc02fd2c0f0f6f04a" }, "downloads": -1, "filename": "gocept.runner-0.6.0.tar.gz", "has_sig": false, "md5_digest": "79ddeb16746be890c0c6c0d325252d3b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16844, "upload_time": "2011-12-01T13:00:08", "url": "https://files.pythonhosted.org/packages/5e/e9/8e43618c7249bc6930274d1271450dbe65b657c57d91f0b8874b5371d2e3/gocept.runner-0.6.0.tar.gz" } ], "0.7.0": [ { "comment_text": "", "digests": { "md5": "a42f2d16bd20adb257602cb3984d2b5e", "sha256": "91b9e0fa6e4d27b1d786f7cac3e6368e4e4501bc0cedd3c8089d01918b77612d" }, "downloads": -1, "filename": "gocept.runner-0.7.0.zip", "has_sig": false, "md5_digest": "a42f2d16bd20adb257602cb3984d2b5e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27976, "upload_time": "2015-01-28T09:18:13", "url": "https://files.pythonhosted.org/packages/e7/52/40ad69e733b2beef0de12bedb0b5bf44f30196d4bced798be1c5f436fa3c/gocept.runner-0.7.0.zip" } ], "0.7.1": [ { "comment_text": "", "digests": { "md5": "edfe6e6b20ad72f2c896f49331ba3e58", "sha256": "62e6fead47f3ad6d07279f2ad7d241433e6c4ce9deaa09fba02654cb2cd49425" }, "downloads": -1, "filename": "gocept.runner-0.7.1.zip", "has_sig": false, "md5_digest": "edfe6e6b20ad72f2c896f49331ba3e58", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29472, "upload_time": "2015-01-28T09:22:44", "url": "https://files.pythonhosted.org/packages/c5/59/71d4455d31417cbd1add665426f264517c2916f827a88ddc6339572c4ad5/gocept.runner-0.7.1.zip" } ], "1.0": [ { "comment_text": "", "digests": { "md5": "1fdc2a4b357293c46a4259d1a7eab7e7", "sha256": "3673e456c1016d95900ea1c2155177297c2e9e9c37c6201664b4a13b743d4086" }, "downloads": -1, "filename": "gocept.runner-1.0.tar.gz", "has_sig": false, "md5_digest": "1fdc2a4b357293c46a4259d1a7eab7e7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18346, "upload_time": "2016-01-12T09:06:28", "url": "https://files.pythonhosted.org/packages/c7/98/56b901167e10e71bfd3a6fee4adda11eb19c9f74cfaf5aac9c9966c9e1b8/gocept.runner-1.0.tar.gz" } ], "2.0": [ { "comment_text": "", "digests": { "md5": "ad744a56c30cc822e6f7d6fe98fcaf7d", "sha256": "abe1623f29a483db38171d748f6bb4f944f23d215742c3bad4da0e628968f96a" }, "downloads": -1, "filename": "gocept.runner-2.0.tar.gz", "has_sig": false, "md5_digest": "ad744a56c30cc822e6f7d6fe98fcaf7d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19057, "upload_time": "2018-03-14T07:35:53", "url": "https://files.pythonhosted.org/packages/48/eb/45d8cdde4fed8fcf39f597384b9d83794a0ba4264a4605c61ec23dc9d9ce/gocept.runner-2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ad744a56c30cc822e6f7d6fe98fcaf7d", "sha256": "abe1623f29a483db38171d748f6bb4f944f23d215742c3bad4da0e628968f96a" }, "downloads": -1, "filename": "gocept.runner-2.0.tar.gz", "has_sig": false, "md5_digest": "ad744a56c30cc822e6f7d6fe98fcaf7d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19057, "upload_time": "2018-03-14T07:35:53", "url": "https://files.pythonhosted.org/packages/48/eb/45d8cdde4fed8fcf39f597384b9d83794a0ba4264a4605c61ec23dc9d9ce/gocept.runner-2.0.tar.gz" } ] }