{ "info": { "author": "", "author_email": "", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "=========\nTaskTiger\n=========\n.. image:: https://circleci.com/gh/closeio/tasktiger/tree/master.svg?style=svg&circle-token=a86617952aa9b4cfee784b6ac43358cd042a6672\n :target: https://circleci.com/gh/closeio/tasktiger/tree/master\n\n*TaskTiger* is a Python task queue using Redis.\n\n\n(Interested in working on projects like this? `Close`_ is looking for `great engineers`_ to join our team)\n\n.. _Close: http://close.com\n.. _great engineers: http://jobs.close.com\n\n\n.. contents:: Contents\n\nFeatures\n--------\n\n- Per-task fork\n\n TaskTiger forks a subprocess for each task, This comes with several benefits:\n Memory leaks caused by tasks are avoided since the subprocess is terminated\n when the task is finished. A hard time limit can be set for each task, after\n which the task is killed if it hasn't completed. To ensure performance, any\n necessary Python modules can be preloaded in the parent process.\n\n- Unique queues\n\n TaskTiger has the option to avoid duplicate tasks in the task queue. In some\n cases it is desirable to combine multiple similar tasks. For example, imagine\n a task that indexes objects (e.g. to make them searchable). If an object is\n already present in the task queue and hasn't been processed yet, a unique\n queue will ensure that the indexing task doesn't have to do duplicate work.\n However, if the task is already running while it's queued, the task will be\n executed another time to ensure that the indexing task always picks up the\n latest state.\n\n- Task locks\n\n TaskTiger can ensure to never execute more than one instance of tasks with\n similar arguments by acquiring a lock. If a task hits a lock, it is requeued\n and scheduled for later executions after a configurable interval.\n\n- Task retrying\n\n TaskTiger lets you retry exceptions (all exceptions or a list of specific\n ones) and comes with configurable retry intervals (fixed, linear,\n exponential, custom).\n\n- Flexible queues\n\n Tasks can be easily queued in separate queues. Workers pick tasks from a\n randomly chosen queue and can be configured to only process specific queues,\n ensuring that all queues are processed equally. TaskTiger also supports\n subqueues which are separated by a period. For example, you can have\n per-customer queues in the form ``process_emails.CUSTOMER_ID`` and start a\n worker to process ``process_emails`` and any of its subqueues. Since tasks\n are picked from a random queue, all customers get equal treatment: If one\n customer is queueing many tasks it can't block other customers' tasks from\n being processed. A maximum queue size can also be enforced.\n\n- Batch queues\n\n Batch queues can be used to combine multiple queued tasks into one. That way,\n your task function can process multiple sets of arguments at the same time,\n which can improve performance. The batch size is configurable.\n\n- Scheduled and periodic tasks\n\n Tasks can be scheduled for execution at a specific time. Tasks can also be\n executed periodically (e.g. every five seconds).\n\n- Structured logging\n\n TaskTiger supports JSON-style logging via structlog, allowing more\n flexibility for tools to analyze the log. For example, you can use TaskTiger\n together with Logstash, Elasticsearch, and Kibana.\n\n The structlog processor ``tasktiger.logging.tasktiger_processor`` can\n be used to inject the current task id into all log messages.\n\n- Reliability\n\n TaskTiger atomically moves tasks between queue states, and will re-execute\n tasks after a timeout if a worker crashes.\n\n- Error handling\n\n If an exception occurs during task execution and the task is not set up to be\n retried, TaskTiger stores the execution tracebacks in an error queue. The\n task can then be retried or deleted manually. TaskTiger can be easily\n integrated with error reporting services like Rollbar.\n\n- Admin interface\n\n A simple admin interface using flask-admin exists as a separate project\n (tasktiger-admin_).\n\n.. _tasktiger-admin: https://github.com/closeio/tasktiger-admin\n\n\nQuick start\n-----------\n\nIt is easy to get started with TaskTiger.\n\nCreate a file that contains the task(s).\n\n.. code:: python\n\n # tasks.py\n def my_task():\n print('Hello')\n\nQueue the task using the ``delay`` method.\n\n.. code:: python\n\n In [1]: import tasktiger, tasks\n In [2]: tiger = tasktiger.TaskTiger()\n In [3]: tiger.delay(tasks.my_task)\n\nRun a worker (make sure the task code can be found, e.g. using ``PYTHONPATH``).\n\n.. code:: bash\n\n % PYTHONPATH=. tasktiger\n {\"timestamp\": \"2015-08-27T21:00:09.135344Z\", \"queues\": null, \"pid\": 69840, \"event\": \"ready\", \"level\": \"info\"}\n {\"task_id\": \"6fa07a91642363593cddef7a9e0c70ae3480921231710aa7648b467e637baa79\", \"level\": \"debug\", \"timestamp\": \"2015-08-27T21:03:56.727051Z\", \"pid\": 69840, \"queue\": \"default\", \"child_pid\": 70171, \"event\": \"processing\"}\n Hello\n {\"task_id\": \"6fa07a91642363593cddef7a9e0c70ae3480921231710aa7648b467e637baa79\", \"level\": \"debug\", \"timestamp\": \"2015-08-27T21:03:56.732457Z\", \"pid\": 69840, \"queue\": \"default\", \"event\": \"done\"}\n\n\nConfiguration\n-------------\n\nA ``TaskTiger`` object keeps track of TaskTiger's settings and is used to\ndecorate and queue tasks. The constructor takes the following arguments:\n\n- ``connection``\n\n Redis connection object. The connection should be initialized with\n ``decode_responses=True`` to avoid encoding problems on Python 3.\n\n- ``config``\n\n Dict with config options. Most configuration options don't need to be\n changed, and a full list can be seen within ``TaskTiger``'s ``__init__``\n method.\n\n Here are a few commonly used options:\n\n - ``ALWAYS_EAGER``\n\n If set to ``True``, all tasks except future tasks (``when`` is a future\n time) will be executed locally by blocking until the task returns. This is\n useful for testing purposes.\n\n - ``BATCH_QUEUES``\n\n Set up queues that will be processed in batch, i.e. multiple jobs are taken\n out of the queue at the same time and passed as a list to the worker\n method. Takes a dict where the key represents the queue name and the value\n represents the batch size. Note that the task needs to be declared as\n ``batch=True``. Also note that any subqueues will be automatically treated\n as batch queues, and the batch value of the most specific subqueue name\n takes precedence.\n\n - ``ONLY_QUEUES``\n\n If set to a non-empty list of queue names, a worker only processes the\n given queues (and their subqueues), unless explicit queues are passed to\n the command line.\n\n- ``setup_structlog``\n\n If set to True, sets up structured logging using ``structlog`` when\n initializing TaskTiger. This makes writing custom worker scripts easier\n since it doesn't require the user to set up ``structlog`` in advance.\n\nExample:\n\n.. code:: python\n\n import tasktiger\n from redis import Redis\n conn = Redis(db=1, decode_responses=True)\n tiger = tasktiger.TaskTiger(connection=conn, config={\n 'BATCH_QUEUES': {\n # Batch up to 50 tasks that are queued in the my_batch_queue or any\n # of its subqueues, except for the send_email subqueue which only\n # processes up to 10 tasks at a time.\n 'my_batch_queue': 50,\n 'my_batch_queue.send_email': 10,\n },\n })\n\n\nTask decorator\n--------------\n\nTaskTiger provides a task decorator to specify task options. Note that simple\ntasks don't need to be decorated. However, decorating the task allows you to\nuse an alternative syntax to queue the task, which is compatible with Celery:\n\n.. code:: python\n\n # tasks.py\n\n import tasktiger\n tiger = tasktiger.TaskTiger()\n\n @tiger.task()\n def my_task(name, n=None):\n print('Hello', name)\n\n.. code:: python\n\n In [1]: import tasks\n # The following are equivalent. However, the second syntax can only be used\n # if the task is decorated.\n In [2]: tasks.tiger.delay(my_task, args=('John',), kwargs={'n': 1})\n In [3]: tasks.my_task.delay('John', n=1)\n\n\nTask options\n------------\n\nTasks support a variety of options that can be specified either in the task\ndecorator, or when queueing a task. For the latter, the ``delay`` method must\nbe called on the ``TaskTiger`` object, and any options in the task decorator\nare overridden.\n\n.. code:: python\n\n @tiger.task(queue='myqueue', unique=True)\n def my_task():\n print('Hello')\n\n.. code:: python\n\n # The task will be queued in \"otherqueue\", even though the task decorator\n # says \"myqueue\".\n tiger.delay(my_task, queue='otherqueue')\n\nWhen queueing a task, the task needs to be defined in a module other than the\nPython file which is being executed. In other words, the task can't be in the\n``__main__`` module. TaskTiger will give you back an error otherwise.\n\nThe following options are supported by both ``delay`` and the task decorator:\n\n- ``queue``\n\n Name of the queue where the task will be queued.\n\n- ``hard_timeout``\n\n If the task runs longer than the given number of seconds, it will be\n killed and marked as failed.\n\n- ``unique``\n\n Boolean to indicate whether the task will only be queued if there is no\n similar task with the same function, arguments, and keyword arguments in the\n queue. Note that multiple similar tasks may still be executed at the same\n time since the task will still be inserted into the queue if another one\n is being processed. Requeueing an already scheduled unique task will not\n change the time it was originally scheduled to execute at.\n\n- ``unique_key``\n\n If set, this implies ``unique=True`` and specifies the list of kwargs to use\n to construct the unique key. By default, all args and kwargs are serialized\n and hashed.\n\n- ``lock``\n\n Boolean to indicate whether to hold a lock while the task is being executed\n (for the given args and kwargs). If a task with similar args/kwargs is queued\n and tries to acquire the lock, it will be retried later.\n\n- ``lock_key``\n\n If set, this implies ``lock=True`` and specifies the list of kwargs to\n use to construct the lock key. By default, all args and kwargs are\n serialized and hashed.\n\n- ``max_queue_size``\n\n A maximum queue size can be enforced by setting this to an integer value.\n The ``QueueFullException`` exception will be raised when queuing a task if\n this limit is reached. Tasks in the ``active``, ``scheduled``, and ``queued``\n states are counted against this limit.\n\n- ``when``\n\n Takes either a datetime (for an absolute date) or a timedelta\n (relative to now). If given, the task will be scheduled for the given\n time.\n\n- ``retry``\n\n Boolean to indicate whether to retry the task when it fails (either because\n of an exception or because of a timeout). To restrict the list of failures,\n use ``retry_on``. Unless ``retry_method`` is given, the configured\n ``DEFAULT_RETRY_METHOD`` is used.\n\n- ``retry_on``\n\n If a list is given, it implies ``retry=True``. The task will be only retried\n on the given exceptions (or its subclasses). To retry the task when a hard\n timeout occurs, use ``JobTimeoutException``.\n\n- ``retry_method``\n\n If given, implies ``retry=True``. Pass either:\n\n - a function that takes the retry number as an argument, or,\n - a tuple ``(f, args)``, where ``f`` takes the retry number as the first\n argument, followed by the additional args.\n\n The function needs to return the desired retry interval in seconds, or raise\n ``StopRetry`` to stop retrying. The following built-in functions can be\n passed for common scenarios and return the appropriate tuple:\n\n - ``fixed(delay, max_retries)``\n\n Returns a method that returns the given ``delay`` (in seconds) or raises\n ``StopRetry`` if the number of retries exceeds ``max_retries``.\n\n - ``linear(delay, increment, max_retries)``\n\n Like ``fixed``, but starts off with the given ``delay`` and increments it\n by the given ``increment`` after every retry.\n\n - ``exponential(delay, factor, max_retries)``\n\n Like ``fixed``, but starts off with the given ``delay`` and multiplies it\n by the given ``factor`` after every retry.\n\n For example, to retry a task 3 times (for a total of 4 executions), and wait\n 60 seconds between executions, pass ``retry_method=fixed(60, 3)``.\n\n- ``runner_class``\n\n If given, a Python class can be specified to influence task running behavior.\n The runner class should inherit ``tasktiger.runner.BaseRunner`` and implement\n the task execution behavior. The default implementation is available in\n ``tasktiger.runner.DefaultRunner``. The following behavior can be achieved:\n\n - Execute specific code before or after the task is executed (in the forked\n child process), or customize the way task functions are called in either\n single or batch processing.\n\n Note that if you want to execute specific code for all tasks,\n you should use the ``CHILD_CONTEXT_MANAGERS`` configuration option.\n\n - Control the hard timeout behavior of a task.\n\n - Execute specific code in the main worker process after a task failed\n permanently.\n\n This is an advanced feature and the interface and requirements of the runner\n class can change in future TaskTiger versions.\n\nThe following options can be only specified in the task decorator:\n\n- ``batch``\n\n If set to ``True``, the task will receive a list of dicts with args and\n kwargs and can process multiple tasks of the same type at once.\n Example: ``[{\"args\": [1], \"kwargs\": {}}, {\"args\": [2], \"kwargs\": {}}]``\n Note that the list will only contain multiple items if the worker\n has set up ``BATCH_QUEUES`` for the specific queue (see the *Configuration*\n section).\n\n- ``schedule``\n\n If given, makes a task execute periodically. Pass either:\n\n - a function that takes the current datetime as an argument.\n - a tuple ``(f, args)``, where ``f`` takes the current datetime as the first\n argument, followed by the additional args.\n\n The schedule function must return the next task execution datetime, or\n ``None`` to prevent periodic execution. The function is executed to determine\n the initial task execution date when a worker is initialized, and to determine\n the next execution date when the task is about to get executed.\n\n For most common scenarios, the ``periodic`` built-in function can be passed:\n\n - ``periodic(seconds=0, minutes=0, hours=0, days=0, weeks=0, start_date=None,\n end_date=None)``\n\n Use equal, periodic intervals, starting from ``start_date`` (defaults to\n ``2000-01-01T00:00Z``, a Saturday, if not given), ending at ``end_date`` (or\n never, if not given). For example, to run a task every five minutes\n indefinitely, use ``schedule=periodic(minutes=5)``. To run a task every\n every Sunday at 4am UTC, you could use\n ``schedule=periodic(weeks=1, start_date=datetime.datetime(2000, 1, 2, 4))``.\n\nCustom retrying\n---------------\n\nIn some cases the task retry options may not be flexible enough. For example,\nyou might want to use a different retry method depending on the exception type,\nor you might want to like to suppress logging an error if a task fails after\nretries. In these cases, ``RetryException`` can be raised within the task\nfunction. The following options are supported:\n\n- ``method``\n\n Specify a custom retry method for this retry. If not given, the task's\n default retry method is used, or, if unspecified, the configured\n ``DEFAULT_RETRY_METHOD``. Note that the number of retries passed to the\n retry method is always the total number of times this method has been\n executed, regardless of which retry method was used.\n\n- ``original_traceback``\n\n If ``RetryException`` is raised from within an except block and\n ``original_traceback`` is True, the original traceback will be logged (i.e.\n the stacktrace at the place where the caught exception was raised). False by\n default.\n\n- ``log_error``\n\n If set to False and the task fails permanently, a warning will be logged\n instead of an error, and the task will be removed from Redis when it\n completes. True by default.\n\nExample usage:\n\n.. code:: python\n\n from tasktiger.exceptions import RetryException\n from tasktiger.retry import exponential, fixed\n\n def my_task():\n if not ready():\n # Retry every minute up to 3 times if we're not ready. An error will\n # be logged if we're out of retries.\n raise RetryException(method=fixed(60, 3))\n\n try:\n some_code()\n except NetworkException:\n # Back off exponentially up to 5 times in case of a network failure.\n # Log the original traceback (as a warning) and don't log an error if\n # we still fail after 5 times.\n raise RetryException(method=exponential(60, 2, 5),\n original_traceback=True,\n log_error=False)\n\n\nWorkers\n-------\n\nThe ``tasktiger`` command is used on the command line to invoke a worker. To\ninvoke multiple workers, multiple instances need to be started. This can be\neasily done e.g. via Supervisor. The following Supervisor configuration file\ncan be placed in ``/etc/supervisor/tasktiger.ini`` and runs 4 TaskTiger workers\nas the ``ubuntu`` user. For more information, read Supervisor's documentation.\n\n.. code:: bash\n\n [program:tasktiger]\n command=/usr/local/bin/tasktiger\n process_name=%(program_name)s_%(process_num)02d\n numprocs=4\n numprocs_start=0\n priority=999\n autostart=true\n autorestart=true\n startsecs=10\n startretries=3\n exitcodes=0,2\n stopsignal=TERM\n stopwaitsecs=600\n killasgroup=false\n user=ubuntu\n redirect_stderr=false\n stdout_logfile=/var/log/tasktiger.out.log\n stdout_logfile_maxbytes=250MB\n stdout_logfile_backups=10\n stderr_logfile=/var/log/tasktiger.err.log\n stderr_logfile_maxbytes=250MB\n stderr_logfile_backups=10\n\nWorkers support the following options:\n\n- ``-q``, ``--queues``\n\n If specified, only the given queue(s) are processed. Multiple queues can be\n separated by comma. Any subqueues of the given queues will be also processed.\n For example, ``-q first,second`` will process items from ``first``,\n ``second``, and subqueues such as ``first.CUSTOMER1``, ``first.CUSTOMER2``.\n\n- ``-e``, ``--exclude-queues``\n\n If specified, exclude the given queue(s) from processing. Multiple queues can\n be separated by comma. Any subqueues of the given queues will also be\n excluded unless a more specific queue is specified with the ``-q`` option.\n For example, ``-q email,email.incoming.CUSTOMER1 -e email.incoming`` will\n process items from the ``email`` queue and subqueues like\n ``email.outgoing.CUSTOMER1`` or ``email.incoming.CUSTOMER1``, but not\n ``email.incoming`` or ``email.incoming.CUSTOMER2``.\n\n- ``-m``, ``--module``\n\n Module(s) to import when launching the worker. This improves task performance\n since the module doesn't have to be reimported every time a task is forked.\n Multiple modules can be separated by comma.\n\n Another way to preload modules is to set up a custom TaskTiger launch script,\n which is described below.\n\n- ``-h``, ``--host``\n\n Redis server hostname (if different from ``localhost``).\n\n- ``-p``, ``--port``\n\n Redis server port (if different from ``6379``).\n\n- ``-a``, ``--password``\n\n Redis server password (if required).\n\n- ``-n``, ``--db``\n\n Redis server database number (if different from ``0``).\n\n- ``-M``, ``--max-workers-per-queue``\n\n Maximum number of workers that are allowed to process a queue.\n\n- ``--store-tracebacks/--no-store-tracebacks``\n\n Store tracebacks with execution history (config defaults to ``True``).\n\nIn some cases it is convenient to have a custom TaskTiger launch script. For\nexample, your application may have a ``manage.py`` command that sets up the\nenvironment and you may want to launch TaskTiger workers using that script. To\ndo that, you can use the ``run_worker_with_args`` method, which launches a\nTaskTiger worker and parses any command line arguments. Here is an example:\n\n.. code:: python\n\n import sys\n from tasktiger import TaskTiger\n\n try:\n command = sys.argv[1]\n except IndexError:\n command = None\n\n if command == 'tasktiger':\n tiger = TaskTiger(setup_structlog=True)\n # Strip the \"tasktiger\" arg when running via manage, so we can run e.g.\n # ./manage.py tasktiger --help\n tiger.run_worker_with_args(sys.argv[2:])\n sys.exit(0)\n\nIf you're using ``flask-script``, you can use the ``TaskTigerCommand`` provided\nin the ``tasktiger.flask_script`` module. It takes the ``TaskTiger`` instance\nas an argument. Tasks will have access to Flask's application context. Example:\n\n.. code:: python\n\n from flask import Flask\n from flask.ext.script import Manager\n from tasktiger.flask_script import TaskTigerCommand\n\n app = Flask()\n manager = Manager(app)\n tiger = TaskTiger(setup_structlog=True)\n\n manager.add_command('tasktiger', TaskTigerCommand(tiger))\n\n if __name__ == \"__main__\":\n manager.run()\n\nYou can subclass the ``TaskTigerCommand`` and override the ``setup`` method to\nimplement any custom setup that needs to be done before running the worker.\n\n\nInspect, requeue and delete tasks\n---------------------------------\n\nTaskTiger provides access to the ``Task`` class which lets you inspect queues\nand perform various actions on tasks.\n\nEach queue can have tasks in the following states:\n\n- ``queued``: Tasks that are queued and waiting to be picked up by the workers.\n- ``active``: Tasks that are currently being processed by the workers.\n- ``scheduled``: Tasks that are scheduled for later execution.\n- ``error``: Tasks that failed with an error.\n\nTo get a list of all tasks for a given queue and state, use\n``Task.tasks_from_queue``. The method gives you back a tuple containing the\ntotal number of tasks in the queue (useful if the tasks are truncated) and a\nlist of tasks in the queue, latest first. Using the ``skip`` and ``limit``\nkeyword arguments, you can fetch arbitrary slices of the queue. If you know the\ntask ID, you can fetch a given task using ``Task.from_id``. Both methods let\nyou load tracebacks from failed task executions using the ``load_executions``\nkeyword argument, which accepts an integer indicating how many executions\nshould be loaded.\n\nTasks can also be constructed and queued using the regular constructor, which\ntakes the TaskTiger instance, the function name and the options described in\nthe *Task options* section. The task can then be queued using its ``delay``\nmethod. Note that the ``when`` argument needs to be passed to the ``delay``\nmethod, if applicable. Unique tasks can be reconstructed using the same\narguments.\n\nThe ``Task`` object has the following properties:\n\n- ``id``: The task ID.\n\n- ``data``: The raw data as a dict from Redis.\n\n- ``executions``: A list of failed task executions (as dicts). An execution\n dict contains the processing time in ``time_started`` and ``time_failed``,\n the worker host in ``host``, the exception name in ``exception_name`` and\n the full traceback in ``traceback``.\n\n- ``serialized_func``, ``args``, ``kwargs``: The serialized function name with\n all of its arguments.\n\n- ``func``: The imported (executable) function\n\nThe ``Task`` object has the following methods:\n\n- ``cancel``: Cancel a scheduled task.\n\n- ``delay``: Queue the task for execution.\n\n- ``delete``: Remove the task from the error queue.\n\n- ``execute``: Run the task without queueing it.\n\n- ``n_executions``: Queries and returns the number of past task executions.\n\n- ``retry``: Requeue the task from the error queue for execution.\n\n- ``update_scheduled_time``: Updates a scheduled task's date to the given date.\n\nThe current task can be accessed within the task function while it's being\nexecuted: In case of a non-batch task, the ``current_task`` property of the\n``TaskTiger`` instance returns the current ``Task`` instance. In case of a\nbatch task the ``current_tasks`` property must be used which returns a list of\ntasks that are currently being processed (in the same order as they were passed\nto the task).\n\nExample 1: Queueing a unique task and canceling it without a reference to the\noriginal task.\n\n.. code:: python\n\n from tasktiger import TaskTiger, Task\n\n tiger = TaskTiger()\n\n # Send an email in five minutes.\n task = Task(tiger, send_mail, args=['email_id'], unique=True)\n task.delay(when=datetime.timedelta(minutes=5))\n\n # Unique tasks get back a task instance referring to the same task by simply\n # creating the same task again.\n task = Task(tiger, send_mail, args=['email_id'], unique=True)\n task.cancel()\n\nExample 2: Inspecting queues and retrying a task by ID.\n\n.. code:: python\n\n from tasktiger import TaskTiger, Task\n\n QUEUE_NAME = 'default'\n TASK_STATE = 'error'\n TASK_ID = '6fa07a91642363593cddef7a9e0c70ae3480921231710aa7648b467e637baa79'\n\n tiger = TaskTiger()\n\n n_total, tasks = Task.tasks_from_queue(tiger, QUEUE_NAME, TASK_STATE)\n\n for task in tasks:\n print(task.id, task.func)\n\n task = Task.from_id(tiger, QUEUE_NAME, TASK_STATE, TASK_ID)\n task.retry()\n\nExample 3: Accessing the task instances within a batch task function to\ndetermine how many times the currently processing tasks were previously\nexecuted.\n\n.. code:: python\n\n from tasktiger import TaskTiger\n\n tiger = TaskTiger()\n\n @tiger.task(batch=True)\n def my_task(args):\n for task in tiger.current_tasks:\n print(task.n_executions())\n\n\nPause queue processing\n----------------------\n\nThe ``--max-workers-per-queue`` option uses queue locks to control the\nnumber of workers that can simultaneously process the same queue. When using\nthis option a system lock can be placed on a queue which will keep workers\nfrom processing tasks from that queue until it expires. Use the\n``set_queue_system_lock()`` method of the TaskTiger object to set this lock.\n\n\nRollbar error handling\n----------------------\n\nTaskTiger comes with Rollbar integration for error handling. When a task errors\nout, it can be logged to Rollbar, grouped by queue, task function name and\nexception type. To enable logging, initialize rollbar with the\n``StructlogRollbarHandler`` provided in the ``tasktiger.rollbar`` module. The\nhandler takes a string as an argument which is used to prefix all the messages\nreported to Rollbar. Here is a custom worker launch script:\n\n.. code:: python\n\n import logging\n import rollbar\n import sys\n from tasktiger import TaskTiger\n from tasktiger.rollbar import StructlogRollbarHandler\n\n tiger = TaskTiger(setup_structlog=True)\n\n rollbar.init(ROLLBAR_API_KEY, APPLICATION_ENVIRONMENT,\n allow_logging_basic_config=False)\n rollbar_handler = StructlogRollbarHandler('TaskTiger')\n rollbar_handler.setLevel(logging.ERROR)\n tiger.log.addHandler(rollbar_handler)\n\n tiger.run_worker_with_args(sys.argv[1:])\n\n\nCleaning Up Error'd Tasks\n-------------------------\n\nError'd tasks occasionally need to be purged from Redis, so ``TaskTiger``\nexposes a ``purge_errored_tasks`` method to help. It might be useful to set\nthis up as a periodic task as follows:\n\n.. code:: python\n\n from tasktiger import TaskTiger, periodic\n\n tiger = TaskTiger()\n\n @tiger.task(schedule=periodic(hours=1))\n def purge_errored_tasks():\n tiger.purge_errored_tasks(\n limit=1000,\n last_execution_before=(\n datetime.datetime.utcnow() - datetime.timedelta(weeks=12)\n )\n )\n\n\nRunning The Test Suite\n----------------------\n\nTests can be run locally using the provided docker compose file. After installing docker, tests should be runnable with:\n\n.. code :: bash\n\n docker-compose run --rm tasktiger pytest\n\nTests can be more granularly run using normal pytest flags. For example:\n\n.. code :: bash\n\n docker-compose run --rm tasktiger pytest tests/test_base.py::TestCase\n\n\nReleasing a New Version\n-----------------------\n\n#. Make sure the code has been thoroughly reviewed and tested in a realistic production environment.\n#. Update ``setup.py`` and ``CHANGELOG.md``. Make sure you include any breaking changes.\n#. Run ``python setup.py sdist`` and ``twine upload dist/``.\n#. Push a new tag pointing to the released commit, format: ``v0.13`` for example.\n#. Mark the tag as a release in GitHub's UI and include in the description the changelog entry for the version.\n An example would be: https://github.com/closeio/tasktiger/releases/tag/v0.13.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/closeio/tasktiger", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "tasktiger", "package_url": "https://pypi.org/project/tasktiger/", "platform": "", "project_url": "https://pypi.org/project/tasktiger/", "project_urls": { "Homepage": "http://github.com/closeio/tasktiger" }, "release_url": "https://pypi.org/project/tasktiger/0.16/", "requires_dist": null, "requires_python": "", "summary": "Python task queue", "version": "0.16", "yanked": false, "yanked_reason": null }, "last_serial": 12192749, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "d6ce23949f2785f41a4fca4dc7b13588", "sha256": "19c547ddf13ac99b8980ba664bf4fac6cc31a80c73105beb4169a17549d73516" }, "downloads": -1, "filename": "tasktiger-0.1.tar.gz", "has_sig": false, "md5_digest": "d6ce23949f2785f41a4fca4dc7b13588", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21573, "upload_time": "2015-10-02T11:05:48", "upload_time_iso_8601": "2015-10-02T11:05:48.502930Z", "url": "https://files.pythonhosted.org/packages/50/05/873fbf6e67b386e65e7319d76704138b28883332b9dccef07c7dfd618ae8/tasktiger-0.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.10.1": [ { "comment_text": "", "digests": { "md5": "94258897cb279f91fb6cf864b5be6059", "sha256": "ed58b0e7981bffbce6fd3a198842dd5a338031721dee24884ee246876da8394b" }, "downloads": -1, "filename": "tasktiger-0.10.1-py3-none-any.whl", "has_sig": false, "md5_digest": "94258897cb279f91fb6cf864b5be6059", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 51715, "upload_time": "2019-10-29T19:32:58", "upload_time_iso_8601": "2019-10-29T19:32:58.510808Z", "url": "https://files.pythonhosted.org/packages/2a/38/3a68437207a23d0ac3e2afe6383d20850ea7f1f8161a20ac7fa671347b55/tasktiger-0.10.1-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "bf6e6a5ec53669d5774312aaae129e47", "sha256": "7a66f4ce55d49a391bece4fe5ba3a368ee4f0a9019148389c391732139e1ac48" }, "downloads": -1, "filename": "tasktiger-0.10.1.tar.gz", "has_sig": false, "md5_digest": "bf6e6a5ec53669d5774312aaae129e47", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 72038, "upload_time": "2019-10-29T19:33:00", "upload_time_iso_8601": "2019-10-29T19:33:00.932496Z", "url": "https://files.pythonhosted.org/packages/2d/d0/fbbcd8af7986262f7c7e9bcb6a560ae8893eeb90beaddc398b86c64f3de4/tasktiger-0.10.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.11": [ { "comment_text": "", "digests": { "md5": "f8bd2d8814f25ca1a951ffcb0aa832a2", "sha256": "04a76ffc24e1b428ba542839c2f48597a92c0e6c83299eadce2c75b9065b2483" }, "downloads": -1, "filename": "tasktiger-0.11.tar.gz", "has_sig": false, "md5_digest": "f8bd2d8814f25ca1a951ffcb0aa832a2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 76240, "upload_time": "2020-06-18T22:08:56", "upload_time_iso_8601": "2020-06-18T22:08:56.130220Z", "url": "https://files.pythonhosted.org/packages/85/16/a20e6823de4464350f736dc15ab54142379b599572aa6fe255a49d364fa2/tasktiger-0.11.tar.gz", "yanked": false, "yanked_reason": null } ], "0.12": [ { "comment_text": "", "digests": { "md5": "35b7cb0199ebb646601b8eb5ab93c583", "sha256": "1ffe3565a23d3d57fa17320b58d6fe02f7786faa5de6c188407129339cfdf236" }, "downloads": -1, "filename": "tasktiger-0.12.tar.gz", "has_sig": false, "md5_digest": "35b7cb0199ebb646601b8eb5ab93c583", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 80717, "upload_time": "2021-03-25T17:50:12", "upload_time_iso_8601": "2021-03-25T17:50:12.128608Z", "url": "https://files.pythonhosted.org/packages/97/97/15d4ff42682b9f80b886d644f4a5a0728b6b934e3cc74801bbb89e2199c6/tasktiger-0.12.tar.gz", "yanked": false, "yanked_reason": null } ], "0.13": [ { "comment_text": "", "digests": { "md5": "4f527fd8ad2e6c1d3a8da2f58df30292", "sha256": "4f91739961ce13bd6c5a141ae12095d387b48ef724e3188acf48bc4b961682a6" }, "downloads": -1, "filename": "tasktiger-0.13.tar.gz", "has_sig": false, "md5_digest": "4f527fd8ad2e6c1d3a8da2f58df30292", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 79105, "upload_time": "2021-03-29T20:43:36", "upload_time_iso_8601": "2021-03-29T20:43:36.775686Z", "url": "https://files.pythonhosted.org/packages/69/14/b1748ec181c0a373f8cb71f7baf19dc84ecb38f586aa70c2045b8bd2a517/tasktiger-0.13.tar.gz", "yanked": false, "yanked_reason": null } ], "0.14": [ { "comment_text": "", "digests": { "md5": "ce7ee6ec29a776eb55fb1a7b290c2fb7", "sha256": "807c450c64237057f094f35f98503369b122f325afee8989fd033e6a97165c74" }, "downloads": -1, "filename": "tasktiger-0.14.tar.gz", "has_sig": false, "md5_digest": "ce7ee6ec29a776eb55fb1a7b290c2fb7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 78698, "upload_time": "2021-04-16T07:36:13", "upload_time_iso_8601": "2021-04-16T07:36:13.909466Z", "url": "https://files.pythonhosted.org/packages/03/df/6a4ac26381bba9256bcb49cf60d5a272a9c47d0dcce3d1b45de20bb4497b/tasktiger-0.14.tar.gz", "yanked": false, "yanked_reason": null } ], "0.15": [ { "comment_text": "", "digests": { "md5": "c8c4d56853c9df7e2b4e26543319d51c", "sha256": "42ecad8da80554297be56e8090b2e8e8568d4f855fc0be2c46a8131c697910ae" }, "downloads": -1, "filename": "tasktiger-0.15.tar.gz", "has_sig": false, "md5_digest": "c8c4d56853c9df7e2b4e26543319d51c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 78776, "upload_time": "2021-04-21T06:12:48", "upload_time_iso_8601": "2021-04-21T06:12:48.332918Z", "url": "https://files.pythonhosted.org/packages/53/ea/b33268c60907d40b5eaac7073e2a2edd05a2ac386b32d783d8336ea4c150/tasktiger-0.15.tar.gz", "yanked": false, "yanked_reason": null } ], "0.16": [ { "comment_text": "", "digests": { "md5": "93cf9a55ebd84128271e232a938921c8", "sha256": "8dc970cb8ffd6ce4da667aefd0cb2a0abc30802f9151444cc0a7c24d7cb9030a" }, "downloads": -1, "filename": "tasktiger-0.16.tar.gz", "has_sig": false, "md5_digest": "93cf9a55ebd84128271e232a938921c8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 74728, "upload_time": "2021-12-02T18:08:25", "upload_time_iso_8601": "2021-12-02T18:08:25.183141Z", "url": "https://files.pythonhosted.org/packages/4e/66/4e6a7d3e33fb51a701c2863b0c66387f365adce379a9608f049b3ecac8b5/tasktiger-0.16.tar.gz", "yanked": false, "yanked_reason": null } ], "0.2": [ { "comment_text": "", "digests": { "md5": "6398dbbed507a9b7a746f727dcc89264", "sha256": "fd93fb8631ca2e9637e98442b57afb0b730ce42757fc1bf748031cdfe17d868f" }, "downloads": -1, "filename": "tasktiger-0.2.tar.gz", "has_sig": false, "md5_digest": "6398dbbed507a9b7a746f727dcc89264", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23785, "upload_time": "2015-11-17T01:02:04", "upload_time_iso_8601": "2015-11-17T01:02:04.189326Z", "url": "https://files.pythonhosted.org/packages/c3/5c/2f9a48c86a0197f1f5cf869e5a27120c028bded26687a344a67395fa8514/tasktiger-0.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3": [ { "comment_text": "", "digests": { "md5": "707e3439f47a5440625795517f6922be", "sha256": "22bd8300415ed342a3befecf861f3377145f1f6e740452f3ecfe9c3b5bb434c8" }, "downloads": -1, "filename": "tasktiger-0.3.tar.gz", "has_sig": false, "md5_digest": "707e3439f47a5440625795517f6922be", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26155, "upload_time": "2016-02-03T19:45:16", "upload_time_iso_8601": "2016-02-03T19:45:16.237874Z", "url": "https://files.pythonhosted.org/packages/13/bc/8c7cbb17fcad49dfa204af118b11cae3ee2be70aa59ffa980c4200a8087a/tasktiger-0.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4": [ { "comment_text": "", "digests": { "md5": "ac0278f35c3c2fed142c71e76ba9e382", "sha256": "66940aa0c58d6e9e4388976ff6d802225d4fc5b9a229b31426c34f8151ff97b8" }, "downloads": -1, "filename": "tasktiger-0.4.tar.gz", "has_sig": false, "md5_digest": "ac0278f35c3c2fed142c71e76ba9e382", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27486, "upload_time": "2016-03-08T00:42:26", "upload_time_iso_8601": "2016-03-08T00:42:26.176053Z", "url": "https://files.pythonhosted.org/packages/3d/a8/ccb5723547717d15833929894bec6bd6f2cb8e47bbbc308c024cc82bfd34/tasktiger-0.4.tar.gz", "yanked": false, "yanked_reason": null } ], "0.5": [ { "comment_text": "", "digests": { "md5": "88e95f340a26895eb054c3ad27f41267", "sha256": "c9cb9f95d8de7d196512b8e1e5b2b27a94021668ef9a3571659b230fb3c2fab9" }, "downloads": -1, "filename": "tasktiger-0.5.tar.gz", "has_sig": false, "md5_digest": "88e95f340a26895eb054c3ad27f41267", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27961, "upload_time": "2016-03-14T19:35:43", "upload_time_iso_8601": "2016-03-14T19:35:43.512340Z", "url": "https://files.pythonhosted.org/packages/95/fa/e9060dcc05c23c99f1cbb142f0d2262c3a995accb376dde869762647937c/tasktiger-0.5.tar.gz", "yanked": false, "yanked_reason": null } ], "0.6": [ { "comment_text": "", "digests": { "md5": "0ae1e9fbcfcf427b550c55432b08923b", "sha256": "2e30ae42e6e85daa7999195fdb12648e3224d7b26a7876a261f88fe201e1c530" }, "downloads": -1, "filename": "tasktiger-0.6.tar.gz", "has_sig": false, "md5_digest": "0ae1e9fbcfcf427b550c55432b08923b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28103, "upload_time": "2016-04-14T09:49:32", "upload_time_iso_8601": "2016-04-14T09:49:32.169748Z", "url": "https://files.pythonhosted.org/packages/22/85/14c9f77715e6e6c797c859cc4e656980a3c66bc6e475a95ea101a4d359b1/tasktiger-0.6.tar.gz", "yanked": false, "yanked_reason": null } ], "0.7": [ { "comment_text": "", "digests": { "md5": "af29fd8ef407ff64dc667b43ead78d26", "sha256": "9723f16202ce13de709b6b705107bfdf9e7b04b802d29148c0e08ce450f7a657" }, "downloads": -1, "filename": "tasktiger-0.7.tar.gz", "has_sig": false, "md5_digest": "af29fd8ef407ff64dc667b43ead78d26", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28244, "upload_time": "2016-05-25T00:31:03", "upload_time_iso_8601": "2016-05-25T00:31:03.009124Z", "url": "https://files.pythonhosted.org/packages/f1/8c/4f5765bd69d5093f2d37e5cd4d1cb50f81b80fc9fdfc33313e291bb850d3/tasktiger-0.7.tar.gz", "yanked": false, "yanked_reason": null } ], "0.8": [ { "comment_text": "", "digests": { "md5": "d60ba0b1fbc5837f272f53d98f02fa5a", "sha256": "9a53d236a47a5476f194e0614e4be17de8c6ac54e3a94f8cb4d265e8c7b53235" }, "downloads": -1, "filename": "tasktiger-0.8.tar.gz", "has_sig": false, "md5_digest": "d60ba0b1fbc5837f272f53d98f02fa5a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29461, "upload_time": "2016-07-08T19:42:38", "upload_time_iso_8601": "2016-07-08T19:42:38.479797Z", "url": "https://files.pythonhosted.org/packages/61/65/e0746a52fb32130917e3a4e9ce35a9cc44a4b5f24210ceeb10b5c30663ac/tasktiger-0.8.tar.gz", "yanked": false, "yanked_reason": null } ], "0.8.1": [ { "comment_text": "", "digests": { "md5": "853f4e4d948dee5c648ec9ddaaac99b9", "sha256": "2ddb93260945015470e18ca9065789b6108191c25a051c00f2dccdbed0b0c762" }, "downloads": -1, "filename": "tasktiger-0.8.1.tar.gz", "has_sig": false, "md5_digest": "853f4e4d948dee5c648ec9ddaaac99b9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29456, "upload_time": "2016-08-11T04:54:31", "upload_time_iso_8601": "2016-08-11T04:54:31.430357Z", "url": "https://files.pythonhosted.org/packages/10/a8/bdc0c3e927f3f077f4dc8098689a26bb7e3daefb2f06fe4126ec06c12f09/tasktiger-0.8.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.8.2": [ { "comment_text": "", "digests": { "md5": "3ef80c41ff2fe99f432115ea56b7ce28", "sha256": "43dee8dd1e6097019cf436fe609ac1484a7990e7386613f76ce1008718c67950" }, "downloads": -1, "filename": "tasktiger-0.8.2.tar.gz", "has_sig": false, "md5_digest": "3ef80c41ff2fe99f432115ea56b7ce28", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29593, "upload_time": "2016-11-16T18:03:32", "upload_time_iso_8601": "2016-11-16T18:03:32.533010Z", "url": "https://files.pythonhosted.org/packages/9a/4b/1264c53579e35364a7d92ea4da40a8e93c3d51f67dd1ff5663dee224015c/tasktiger-0.8.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.8.3": [ { "comment_text": "", "digests": { "md5": "7cc293dbb3b8f032afc7fa2693277973", "sha256": "fe08b4dfb596e836914d09f532d21d51219a16b072aaa2a2573fdf81851eee10" }, "downloads": -1, "filename": "tasktiger-0.8.3.tar.gz", "has_sig": false, "md5_digest": "7cc293dbb3b8f032afc7fa2693277973", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30284, "upload_time": "2016-12-09T00:04:58", "upload_time_iso_8601": "2016-12-09T00:04:58.800236Z", "url": "https://files.pythonhosted.org/packages/fa/e1/0f0227040ab6c8fa1fb870682c3eccb217ab7f0e897130bb702f7318163b/tasktiger-0.8.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.8.4": [ { "comment_text": "", "digests": { "md5": "61232cec6f79635e98039e7bd8631023", "sha256": "8d07a9669ea20ab11fe90e0cb8b5e5814600f8e072400c0b65c5b80b1664dd90" }, "downloads": -1, "filename": "tasktiger-0.8.4.tar.gz", "has_sig": false, "md5_digest": "61232cec6f79635e98039e7bd8631023", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32113, "upload_time": "2017-01-10T23:23:21", "upload_time_iso_8601": "2017-01-10T23:23:21.137536Z", "url": "https://files.pythonhosted.org/packages/8c/27/8ad49d33a6a62be9fb9e51533a84f03dedfe3b573431031cfcbadefa5009/tasktiger-0.8.4.tar.gz", "yanked": false, "yanked_reason": null } ], "0.8.5": [ { "comment_text": "", "digests": { "md5": "3edfe03a4385a483bf29cbf2108a6f32", "sha256": "99c5e7b263e95cd860ff82e09923b3dba9962b32db6afd49b4775446d47ed571" }, "downloads": -1, "filename": "tasktiger-0.8.5.tar.gz", "has_sig": false, "md5_digest": "3edfe03a4385a483bf29cbf2108a6f32", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33169, "upload_time": "2017-04-11T01:25:26", "upload_time_iso_8601": "2017-04-11T01:25:26.368714Z", "url": "https://files.pythonhosted.org/packages/8b/7d/dc2ec1904ddd025f58978a4829bbe79cebd4ffa6a9705cdb6fbb45e3bd4c/tasktiger-0.8.5.tar.gz", "yanked": false, "yanked_reason": null } ], "0.9": [], "0.9.1": [ { "comment_text": "", "digests": { "md5": "e3cdc886c9d527e526800242f883a79f", "sha256": "2da37de77144a2acc8ccb036f5ed575ec5f825770ca296844256db6309eeed3a" }, "downloads": -1, "filename": "tasktiger-0.9.1.tar.gz", "has_sig": false, "md5_digest": "e3cdc886c9d527e526800242f883a79f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35664, "upload_time": "2017-05-24T22:33:07", "upload_time_iso_8601": "2017-05-24T22:33:07.077270Z", "url": "https://files.pythonhosted.org/packages/df/cb/1cbe369c619de6cff6bc290c90305e997302953b2207162d0e01e3879a71/tasktiger-0.9.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.9.2": [ { "comment_text": "", "digests": { "md5": "4db69f67272be27cf2f43dbdb54bcf99", "sha256": "e56708b779c8d65eae56618fd2f445bc487c8a8ac8e1a5070a5b257aaa98370c" }, "downloads": -1, "filename": "tasktiger-0.9.2.tar.gz", "has_sig": false, "md5_digest": "4db69f67272be27cf2f43dbdb54bcf99", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 59080, "upload_time": "2017-09-29T20:20:32", "upload_time_iso_8601": "2017-09-29T20:20:32.579336Z", "url": "https://files.pythonhosted.org/packages/8a/36/19c671eabf2c8fea8a862cea559ec9ef0f140ead39437470d6287d8ff368/tasktiger-0.9.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.9.3": [ { "comment_text": "", "digests": { "md5": "4ee7a4525fc6728da9c688573f54ac86", "sha256": "8ad532ef217cdc2e67035806a05f160ab2e3d59a758ebce34e93817207ba5760" }, "downloads": -1, "filename": "tasktiger-0.9.3.tar.gz", "has_sig": false, "md5_digest": "4ee7a4525fc6728da9c688573f54ac86", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 59734, "upload_time": "2018-01-09T20:09:10", "upload_time_iso_8601": "2018-01-09T20:09:10.949784Z", "url": "https://files.pythonhosted.org/packages/4e/40/01a6bf90d5f105c574178ca0af5376aa611f64a0b1122a67dd4cda9aa32b/tasktiger-0.9.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.9.4": [ { "comment_text": "", "digests": { "md5": "1c128f24543ff27162ca966409bb46f5", "sha256": "44e18244d5d1607cdd410fd9079e1093e77f9099302f759425154b01d8c5b248" }, "downloads": -1, "filename": "tasktiger-0.9.4.tar.gz", "has_sig": false, "md5_digest": "1c128f24543ff27162ca966409bb46f5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 59967, "upload_time": "2018-07-24T20:16:00", "upload_time_iso_8601": "2018-07-24T20:16:00.100251Z", "url": "https://files.pythonhosted.org/packages/64/ec/c7042e3891cf871445d11955bd3059c7772708d921a5601665b6851053d5/tasktiger-0.9.4.tar.gz", "yanked": false, "yanked_reason": null } ], "0.9.5": [ { "comment_text": "", "digests": { "md5": "e4c1ed88093e6b6f742033b4872f4adf", "sha256": "d0983cf3cf78f4759a245b54ceae97f5de014a9d13b6340bee7e924d1c31d14e" }, "downloads": -1, "filename": "tasktiger-0.9.5-py3-none-any.whl", "has_sig": false, "md5_digest": "e4c1ed88093e6b6f742033b4872f4adf", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 48893, "upload_time": "2019-07-30T11:25:36", "upload_time_iso_8601": "2019-07-30T11:25:36.617743Z", "url": "https://files.pythonhosted.org/packages/3a/37/0d6ea218682a28ce104a9bd8d505a31f092836fb8311db7eab9cbc78047f/tasktiger-0.9.5-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "633394e2fc2c1f032870dc1e6e2cba46", "sha256": "62d06fb79fc9350f28e82b376c07a28dfbbf5c3c941cd9408058117a055cc93c" }, "downloads": -1, "filename": "tasktiger-0.9.5.tar.gz", "has_sig": false, "md5_digest": "633394e2fc2c1f032870dc1e6e2cba46", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66018, "upload_time": "2019-07-30T11:25:38", "upload_time_iso_8601": "2019-07-30T11:25:38.449518Z", "url": "https://files.pythonhosted.org/packages/ed/fe/e705e018c566994b44ef14a1466e41b66732ae3ba82aa3771b27a0a0103c/tasktiger-0.9.5.tar.gz", "yanked": false, "yanked_reason": null } ], "0.9.6": [ { "comment_text": "", "digests": { "md5": "6bad475194bd1f44a1e6571a49ec92e8", "sha256": "7d6082f0459f2bea5881f31886ecb872e574459494c54cec0a71dfde5ffa0fc9" }, "downloads": -1, "filename": "tasktiger-0.9.6.tar.gz", "has_sig": false, "md5_digest": "6bad475194bd1f44a1e6571a49ec92e8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66461, "upload_time": "2019-09-12T19:17:19", "upload_time_iso_8601": "2019-09-12T19:17:19.292626Z", "url": "https://files.pythonhosted.org/packages/2c/4d/b280e11ac9cfdfb92acf2348b02eff85498fe444293a7443496f96e1e779/tasktiger-0.9.6.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "93cf9a55ebd84128271e232a938921c8", "sha256": "8dc970cb8ffd6ce4da667aefd0cb2a0abc30802f9151444cc0a7c24d7cb9030a" }, "downloads": -1, "filename": "tasktiger-0.16.tar.gz", "has_sig": false, "md5_digest": "93cf9a55ebd84128271e232a938921c8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 74728, "upload_time": "2021-12-02T18:08:25", "upload_time_iso_8601": "2021-12-02T18:08:25.183141Z", "url": "https://files.pythonhosted.org/packages/4e/66/4e6a7d3e33fb51a701c2863b0c66387f365adce379a9608f049b3ecac8b5/tasktiger-0.16.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }