{ "info": { "author": "Cameron Maske", "author_email": "cameronmaske@gmail.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: System :: Distributed Computing" ], "description": "Celery Once\n===========\n\n|Build Status| |Coverage Status|\n\nCelery Once allows you to prevent multiple execution and queuing of `celery `_ tasks.\n\nInstallation\n============\n\nInstalling ``celery_once`` is simple with pip, just run:\n\n::\n\n pip install -U celery_once\n\n\nRequirements\n============\n\n* `Celery `__. Built to run with Celery 4.0. Older versions may work, but are not officially supported.\n\nUsage\n=====\n\nTo use ``celery_once``, your tasks need to inherit from an `abstract `_ base task called ``QueueOnce``.\n\nOnce installed, you'll need to configure a few options a ``ONCE`` key in celery's conf.\n\n.. code:: python\n\n from celery import Celery\n from celery_once import QueueOnce\n from time import sleep\n\n celery = Celery('tasks', broker='amqp://guest@localhost//')\n celery.conf.ONCE = {\n 'backend': 'celery_once.backends.Redis',\n 'settings': {\n 'url': 'redis://localhost:6379/0',\n 'default_timeout': 60 * 60\n }\n }\n\n @celery.task(base=QueueOnce)\n def slow_task():\n sleep(30)\n return \"Done!\"\n\n\nThe exact configuration, depends on which locking backend you want to use. See `Backends`_.\n\n\nBehind the scenes, this overrides ``apply_async`` and ``delay``. It does not affect calling the tasks directly.\n\nWhen running the task, ``celery_once`` checks that no lock is in place (against a Redis key).\nIf it isn't, the task will run as normal. Once the task completes (or ends due to an exception) the lock will clear.\nIf an attempt is made to run the task again before it completes an ``AlreadyQueued`` exception will be raised.\n\n.. code-block:: python\n\n example.delay(10)\n example.delay(10)\n Traceback (most recent call last):\n ..\n AlreadyQueued()\n\n.. code-block:: python\n\n result = example.apply_async(args=(10))\n result = example.apply_async(args=(10))\n Traceback (most recent call last):\n ..\n AlreadyQueued()\n\n\n``graceful``\n------------\n\nOptionally, instead of raising an ``AlreadyQueued`` exception, the task can return ``None`` if ``once={'graceful': True}`` is set in the task's `options `__ or when run through ``apply_async``.\n\n.. code:: python\n\n from celery_once import AlreadyQueued\n # Either catch the exception,\n try:\n example.delay(10)\n except AlreadyQueued:\n pass\n # Or, handle it gracefully at run time.\n result = example.apply(args=(10), once={'graceful': True})\n # or by default.\n @celery.task(base=QueueOnce, once={'graceful': True})\n def slow_task():\n sleep(30)\n return \"Done!\"\n\n\n``keys``\n--------\n\nBy default ``celery_once`` creates a lock based on the task's name and its arguments and values.\nTake for example, the following task below...\n\n.. code:: python\n\n @celery.task(base=QueueOnce)\n def slow_add(a, b):\n sleep(30)\n return a + b\n\nRunning the task with different arguments will default to checking against different locks.\n\n.. code:: python\n\n slow_add(1, 1)\n slow_add(1, 2)\n\nIf you want to specify locking based on a subset, or no arguments you can adjust the keys ``celery_once`` looks at in the task's `options `_ with ``once={'keys': [..]}``\n\n.. code:: python\n\n @celery.task(base=QueueOnce, once={'keys': ['a']})\n def slow_add(a, b):\n sleep(30)\n return a + b\n\n example.delay(1, 1)\n # Checks if any tasks are running with the `a=1`\n example.delay(1, 2)\n Traceback (most recent call last):\n ..\n AlreadyQueued()\n example.delay(2, 2)\n\n.. code:: python\n\n @celery.task(base=QueueOnce, once={'keys': []})\n def slow_add(a, b):\n sleep(30)\n return a + b\n\n # Will enforce only one task can run, no matter what arguments.\n example.delay(1, 1)\n example.delay(2, 2)\n Traceback (most recent call last):\n ..\n AlreadyQueued()\n\n\n``timeout``\n-----------\nAs a fall back, ``celery_once`` will clear a lock after 60 minutes.\nThis is set globally in Celery's configuration with ``ONCE_DEFAULT_TIMEOUT`` but can be set for individual tasks using...\n\n.. code:: python\n\n @celery.task(base=QueueOnce, once={'timeout': 60 * 60 * 10})\n def long_running_task():\n sleep(60 * 60 * 3)\n\n\n``unlock_before_run``\n---------------------\nBy default, the lock is removed after the task has executed (using celery's `after_return `_). This behaviour can be changed setting the task's option ``unlock_before_run``. When set to ``True``, the lock will be removed just before executing the task.\n\n**Caveats**:\n * Any retry of the task won't re-enable the lock!\n * This can only be set when defining the task, it cannot be passed dynamically to ``apply_async``\n\n.. code:: python\n\n @celery.task(base=QueueOnce, once={'unlock_before_run': True})\n def slow_task():\n sleep(30)\n return \"Done!\"\n\n\n\n\nBackends\n========\n\nRedis Backend\n-------------\n\nRequires:\n\n* `Redis `_ is used as a distributed locking mechanism. Behind the scenes, it use redis-py's `shared, distributed Lock `_.\n\nConfiguration:\n\n- ``backend`` - ``celery_once.backends.Redis``\n\n- ``settings``\n\n - ``default_timeout`` - how many seconds after a lock has been set before it should automatically timeout (defaults to 3600 seconds, or 1 hour).\n\n - ``url`` - should point towards a running Redis instance (defaults to ``redis://localhost:6379/0``). See below for the format options supported\n\n - ``blocking`` (boolean value: default ``False``) - If set to ``True``, scheduling a task (by ``.delay/.apply_async``) will block for X seconds to acquire the lock (see: ``blocking_timeout`` below). If no lock could be acquired after X seconds, will raise an ``AlreadyQueued`` exception. This is a very specific use-case scenario and by default is disabled.\n\n - ``blocking_timeout`` (int or float value: default ``1``) - How many seconds the task will block trying to aquire the lock, if ``blocking`` is set to ``True``. Setting this to ``None`` set's no timeout (equivalent to infinite seconds).\n\n\n\nThe URL parser supports three patterns of urls:\n\n* ``redis://host:port[/db][?options]``: redis over TCP\n\n* ``rediss://host:port[/db][?options]``: redis over TCP with SSL enabled.\n\n* ``redis+socket:///path/to/redis.sock[?options]``: redis over a UNIX socket\n\n The ``options`` query args are mapped to the `StrictRedis `_ keyword args.\n Examples:\n * ``redis://localhost:6379/1``\n \n * ``redis://localhost:6379/1?ssl=true``\n\n * ``rediss://localhost:6379/1``\n\n * ``redis+socket:///var/run/redis/redis.sock?db=1``\n\n\nExample Configuration:\n\nMinimal:\n\n.. code:: python\n\n celery.conf.ONCE = {\n 'backend': 'celery_once.backends.Redis',\n 'settings': {\n 'url': 'redis://localhost:6379/0',\n 'default_timeout': 60 * 60\n }\n }\n\n\nAdvanced:\nScheduling tasks blocks up to 30 seconds trying to acquire a lock before raising an exception.\n\n .. code:: python\n\n celery.conf.ONCE = {\n 'backend': 'celery_once.backends.Redis',\n 'settings': {\n 'url': 'redis://localhost:6379/0',\n 'default_timeout': 60 * 60,\n 'blocking': True,\n 'blocking_timeout': 30\n }\n }\n\nFile Backend\n-------------\n\nConfiguration:\n\n- ``backend`` - ``celery_once.backends.File``\n\n- ``settings``\n\n - ``location`` - directory where lock files will be located. Default is temporary directory.\n\n - ``default_timeout`` - how many seconds after a lock has been set before it should automatically timeout (defaults to 3600 seconds, or 1 hour).\n\n\nExample Configuration:\n\n.. code:: python\n\n celery.conf.ONCE = {\n 'backend': 'celery_once.backends.File',\n 'settings': {\n 'location': '/tmp/celery_once',\n 'default_timeout': 60 * 60\n }\n }\n\n\nFlask Intergration\n------------------\nTo avoid ``RuntimeError: Working outside of application context`` errors when using ``celery_once`` with `Flask `_, you need to make the ``QueueOnce`` task base class application context aware.\nIf you've implemented Celery following the Flask `documentation `_ you can extend it like so.\n\n .. code:: python\n\n def make_celery(app):\n celery = Celery(\n app.import_name,\n backend=app.config['CELERY_RESULT_BACKEND'],\n broker=app.config['CELERY_BROKER_URL']\n )\n celery.conf.update(app.config)\n\n class ContextTask(celery.Task):\n def __call__(self, *args, **kwargs):\n with app.app_context():\n return self.run(*args, **kwargs)\n celery.Task = ContextTask\n\n # Make QueueOnce app context aware.\n class ContextQueueOnce(QueueOnce):\n def __call__(self, *args, **kwargs):\n with app.app_context():\n return super(ContextQueueOnce, self).__call__(*args, **kwargs)\n\n # Attach to celery object for easy access.\n celery.QueueOnce = ContextQueueOnce\n return celery\n\n\nNow, when instead of importing the ``QueueOnce`` base, you can use the context aware base on the ``celery`` object.\n\n .. code:: python\n\n celery = make_celery(app)\n\n @celery.task(base=celery.QueueOnce)\n def example_task(value):\n return\n\n\nCustom Backend\n--------------\n\nIf you want to implement a custom locking backend, see `BACKEND\\_GUIDE.rst`_.\n\n.. _BACKEND\\_GUIDE.rst: BACKEND_GUIDE.rst\n\nSupport\n=======\n\n* Tests are run against Python 2.7, 3.4 and 3.5. Other versions may work, but are not officially supported.\n\nContributing\n============\n\nContributions are welcome, and they are greatly appreciated! See `contributing\nguide `_ for more details.\n\n\n.. |Build Status| image:: https://travis-ci.org/cameronmaske/celery-once.svg\n :target: https://travis-ci.org/cameronmaske/celery-once\n.. |Coverage Status| image:: https://coveralls.io/repos/cameronmaske/celery-once/badge.svg\n :target: https://coveralls.io/r/cameronmaske/celery-once\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/cameronmaske/celery-once", "keywords": "celery", "license": "BSD", "maintainer": "", "maintainer_email": "", "name": "celery_once", "package_url": "https://pypi.org/project/celery_once/", "platform": "", "project_url": "https://pypi.org/project/celery_once/", "project_urls": { "Homepage": "https://github.com/cameronmaske/celery-once" }, "release_url": "https://pypi.org/project/celery_once/3.0.1/", "requires_dist": null, "requires_python": "", "summary": "Allows you to prevent multiple execution and queuing of celery tasks.", "version": "3.0.1" }, "last_serial": 5710245, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "181b2718565fd7299e8723beae7cb6dd", "sha256": "2411c9b821487470b5cc2a3f206bd1bedc243a362d97198c6e07936b422699bd" }, "downloads": -1, "filename": "celery_once-0.1.tar.gz", "has_sig": false, "md5_digest": "181b2718565fd7299e8723beae7cb6dd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5749, "upload_time": "2015-01-30T20:52:51", "url": "https://files.pythonhosted.org/packages/28/39/12f710eb5ef1baadb670710f041ac292d5e15568553b3d98244404537718/celery_once-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "02fb58675b4eadaefa588023197d3ad6", "sha256": "ba850698fa360810eda7eb52e2a38a4ee7d1ee6f1f17284f5d10e8e1f00d1326" }, "downloads": -1, "filename": "celery_once-0.1.1.tar.gz", "has_sig": false, "md5_digest": "02fb58675b4eadaefa588023197d3ad6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6060, "upload_time": "2015-02-27T02:24:42", "url": "https://files.pythonhosted.org/packages/d0/51/b589d477c0f08aacdcedf72370dcb4fe0216908432e3b2fd195829961a9a/celery_once-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "f2596048a7d40ffe8c2215af39489666", "sha256": "c9c6ed3c48a752841e50d036e68a8898d2b21a4427b171bbf55402e690427177" }, "downloads": -1, "filename": "celery_once-0.1.2.tar.gz", "has_sig": false, "md5_digest": "f2596048a7d40ffe8c2215af39489666", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6628, "upload_time": "2015-03-16T03:07:33", "url": "https://files.pythonhosted.org/packages/4f/67/65efbdcd3d6cec5e5d9050bfec2530108333377ca7e6045de8d6c1734759/celery_once-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "c5ad5cf10968b5f4cef3d19ec1e98376", "sha256": "4640281ff0fee61f6321be17fa7d5c30d4934b28962295d85735dda8123f35ba" }, "downloads": -1, "filename": "celery_once-0.1.3.tar.gz", "has_sig": false, "md5_digest": "c5ad5cf10968b5f4cef3d19ec1e98376", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6938, "upload_time": "2015-07-14T16:10:50", "url": "https://files.pythonhosted.org/packages/6e/ca/cc1278268b5302b7d0ea18055161d558736127c4841ae292e6c1e995b0de/celery_once-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "d33f800151c1ac3e99de97c6c11fdd52", "sha256": "f3e330b2bef8c952145b77275004db8c4bb6409850bbbca90115285349f007fe" }, "downloads": -1, "filename": "celery_once-0.1.4.tar.gz", "has_sig": false, "md5_digest": "d33f800151c1ac3e99de97c6c11fdd52", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6976, "upload_time": "2015-07-29T21:47:56", "url": "https://files.pythonhosted.org/packages/0c/eb/4a1966b5ca68d0c5600c9eb7bf627de8cb8dcf01f68077fb9e97c9121283/celery_once-0.1.4.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "a013a504ba92a7cb6fae42dca2fd36b4", "sha256": "22b2f8b0f088927b9e68545f8d239e8f90818714a31c189aab2a4d1d84925ed2" }, "downloads": -1, "filename": "celery_once-1.0.0.tar.gz", "has_sig": false, "md5_digest": "a013a504ba92a7cb6fae42dca2fd36b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9515, "upload_time": "2017-06-06T08:49:25", "url": "https://files.pythonhosted.org/packages/64/28/67040127279db925142ddc112b9cd50ae5474336fe51e9cf3f1b87b9fb76/celery_once-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "023ed5589471de6a93da507366cb35bc", "sha256": "1b75127a89fb28ce56ad43595a2046b4b3c3d4cbe3052965c69d90fdd09a3289" }, "downloads": -1, "filename": "celery_once-1.0.1.tar.gz", "has_sig": false, "md5_digest": "023ed5589471de6a93da507366cb35bc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10282, "upload_time": "2017-06-06T15:07:51", "url": "https://files.pythonhosted.org/packages/8e/e3/f4332ed46eada0d96764e69f79fa15371e0f22325ddc339d1195c0ff3b08/celery_once-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "4a617c2d51b5d0888094f032444ff1ca", "sha256": "475671cb8c2e16043bd8b96dbe09eb04744e63fb955c1f0c778cc64f74e6a69e" }, "downloads": -1, "filename": "celery_once-1.0.2.tar.gz", "has_sig": false, "md5_digest": "4a617c2d51b5d0888094f032444ff1ca", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10356, "upload_time": "2017-06-06T15:22:47", "url": "https://files.pythonhosted.org/packages/d3/31/379f744074d9eac3ae8fc79f5c52b19f42b03398b6914ae9a6ba6c56134e/celery_once-1.0.2.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "b976713daa21754e318a1bb386884678", "sha256": "66752e091f052aeabbe4f03d9e53069b1092ac5350e295fc99c0ce033f4cfc80" }, "downloads": -1, "filename": "celery_once-1.1.0.tar.gz", "has_sig": false, "md5_digest": "b976713daa21754e318a1bb386884678", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7716, "upload_time": "2017-06-12T09:24:52", "url": "https://files.pythonhosted.org/packages/e3/81/ad93fb9635713fce2de79ff21b04c194a803a7cfdaefcafa8ca5ab1f2173/celery_once-1.1.0.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "cb21952d621f12044de72fb537af7b6c", "sha256": "53139fb022e1f877e5515a11a34bac80d03745842606c20b70a5820f87e8e68d" }, "downloads": -1, "filename": "celery_once-1.2.0.tar.gz", "has_sig": false, "md5_digest": "cb21952d621f12044de72fb537af7b6c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7738, "upload_time": "2017-06-12T09:44:11", "url": "https://files.pythonhosted.org/packages/82/f8/052e910c3c4ecf699dc1914d8ef001f25aafe0f00ed4320af1f3faa35694/celery_once-1.2.0.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "5996613f21de83610d25f87ca4a4ae05", "sha256": "041d319ae14f1eae15a23f577dd930d1e57651b628c11642797d98e328f1af64" }, "downloads": -1, "filename": "celery_once-1.3.0.tar.gz", "has_sig": false, "md5_digest": "5996613f21de83610d25f87ca4a4ae05", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7896, "upload_time": "2018-04-25T13:01:32", "url": "https://files.pythonhosted.org/packages/71/0e/8634f2466090cc94d347c3657164459aaf72ca8784ef30eb26656c219f3a/celery_once-1.3.0.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "98216dfb37c2fccb9e65bede77c671eb", "sha256": "a25072b6c524379cb15b1aadc1cdd5f01cda5220a6e2f04375d2b9c56222ad1a" }, "downloads": -1, "filename": "celery_once-2.0.0.tar.gz", "has_sig": false, "md5_digest": "98216dfb37c2fccb9e65bede77c671eb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8317, "upload_time": "2018-04-26T08:55:07", "url": "https://files.pythonhosted.org/packages/f5/86/ddb465309061b401b31b560b76a0d446118f97634cb5bfdc797649ccdfcc/celery_once-2.0.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "ad8f35c66132889b43f2721a2d9cde1e", "sha256": "cf6639952e9918bb79298e8863ba47b3e9cd5db30012f3d312d1a4047778c3bc" }, "downloads": -1, "filename": "celery_once-2.0.1.tar.gz", "has_sig": false, "md5_digest": "ad8f35c66132889b43f2721a2d9cde1e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8920, "upload_time": "2019-02-25T15:36:53", "url": "https://files.pythonhosted.org/packages/cd/1a/0a7adcdccfdf6fb27b09b323f5caabdf351478654583b19324817bfd156c/celery_once-2.0.1.tar.gz" } ], "2.1.0": [ { "comment_text": "", "digests": { "md5": "f76db4d65e311819fb7851dcf05f3262", "sha256": "02e464e60e5610c7832d68108550bedc5ccf175ce8d8b087ce9849eed230cfb9" }, "downloads": -1, "filename": "celery_once-2.1.0.tar.gz", "has_sig": false, "md5_digest": "f76db4d65e311819fb7851dcf05f3262", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12274, "upload_time": "2019-02-25T16:42:09", "url": "https://files.pythonhosted.org/packages/64/10/fac8a2e97e576647abb04831f6a92cdca4b3a25eb9240d4c590b4c698c39/celery_once-2.1.0.tar.gz" } ], "2.1.1": [ { "comment_text": "", "digests": { "md5": "1a580570e81fd55f28f7d71f42d9dffb", "sha256": "123abf4750324affa62a09b5a92619b83359d8b56f96d86312f203f4dda4e5d8" }, "downloads": -1, "filename": "celery_once-2.1.1.tar.gz", "has_sig": false, "md5_digest": "1a580570e81fd55f28f7d71f42d9dffb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12393, "upload_time": "2019-05-08T11:31:41", "url": "https://files.pythonhosted.org/packages/7c/27/89164e9a7a50a874b103887bdeee17c6b61d4334b419259505c921e0aceb/celery_once-2.1.1.tar.gz" } ], "2.1.2": [ { "comment_text": "", "digests": { "md5": "0db9902efe902e6cc694151392c8870b", "sha256": "fddb2bc10bb26b8fa0af959250625c51d2a16f6b640096ff278249d6209ef484" }, "downloads": -1, "filename": "celery_once-2.1.2.tar.gz", "has_sig": false, "md5_digest": "0db9902efe902e6cc694151392c8870b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12469, "upload_time": "2019-05-13T12:27:52", "url": "https://files.pythonhosted.org/packages/94/48/c14b78e7ab49149f97e71f697e0bbdd13d2d1295e312fd37501827c3376b/celery_once-2.1.2.tar.gz" } ], "3.0.0": [ { "comment_text": "", "digests": { "md5": "e6800802d7539730a15992d517610476", "sha256": "d04e5417fb28543ef3b9c6c9df8d5de8c8410a1ffbce4e376acafa14d5d93d80" }, "downloads": -1, "filename": "celery_once-3.0.0.tar.gz", "has_sig": false, "md5_digest": "e6800802d7539730a15992d517610476", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12643, "upload_time": "2019-05-13T12:46:46", "url": "https://files.pythonhosted.org/packages/0d/8b/8758e7857f066b49283cdebd1dd3e3b2549dce06ab24fae6e3955e914db0/celery_once-3.0.0.tar.gz" } ], "3.0.1": [ { "comment_text": "", "digests": { "md5": "4baf1604365deee1a366e2d16d0c0329", "sha256": "9098730d6a84a91ccd84868c4730a81487fd0ffb7220cb1836d2b928542159d0" }, "downloads": -1, "filename": "celery_once-3.0.1.tar.gz", "has_sig": false, "md5_digest": "4baf1604365deee1a366e2d16d0c0329", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12692, "upload_time": "2019-08-21T15:00:37", "url": "https://files.pythonhosted.org/packages/07/ff/af718344bfa9e0e25fb6855095a928ac6525f23b14a3998dd99699dfdee0/celery_once-3.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4baf1604365deee1a366e2d16d0c0329", "sha256": "9098730d6a84a91ccd84868c4730a81487fd0ffb7220cb1836d2b928542159d0" }, "downloads": -1, "filename": "celery_once-3.0.1.tar.gz", "has_sig": false, "md5_digest": "4baf1604365deee1a366e2d16d0c0329", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12692, "upload_time": "2019-08-21T15:00:37", "url": "https://files.pythonhosted.org/packages/07/ff/af718344bfa9e0e25fb6855095a928ac6525f23b14a3998dd99699dfdee0/celery_once-3.0.1.tar.gz" } ] }