# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['bufferq']

package_data = \
{'': ['*']}

setup_kwargs = {
    'name': 'bufferq',
    'version': '0.0.3',
    'description': 'Queue Library with an improved interface.',
    'long_description': '# bufferq\n\nBetter Queue Interface for Python\n\nPython\'s `queue` interface is quite clunky and really not that good.\n\n`bufferq` is a separate queue implementation with a more intuitive interface.\n\n## Sample Usage\n\nQueues from `bufferq` are simple to use with a simple interface:\n```python\nimport threading\nimport bufferq\n\nq = bufferq.Queue()\n\ndef consumer(q):\n    for item in q.consume_one_generator():\n        print(f"Working on item: {item}")\n\nthd = threading.Thread(target=consumer, args=(q,))\nthd.daemon = True\nthd.start()\n\nq.put(\'a\')\nq.put(\'b\')\ntime.sleep(1)\nq.put_multi(list(range(5)))\n\nq.stop()\nthd.join()\n```\n\n## What\'s Wrong with `queue`?\n\nHere are a few issues:\n\n### Basic Operations\n\nPython\'s `queue` interface is surprisingly overwhelming for simple tasks.\n\nFor example, adding/pushing items to the queue.\n`queue.Queue.put()` has three different arguments:\n 1. The item\n 2. blocking (why?)\n 3. timeout\n(Options 2 and 3 are set so the operation blocks indefinitely until the\nitem can be added.)\n\nThis is annoying; why have `blocking` and `timeout` as separate arguments,\ninstead of simply letting `timeout=0` (or maybe even some placeholder-style\nobject if you are really, _REALLY_ concerned about blocking)? A `timeout=0`\nshould imply a single lookup that fails with `queue.Empty` if nothing is in\nthe queue without any additional arguments.\nYes, there is an added "convenience" call of `queue.Queue.put_nowait()`,\nbut this can just as easily be a proxy call to: `put(item, timeout=0)` or\nsimilar without muddying the primary call for the interface.\n\nThis same problem exists (and is more relevant) for the `get()` calls for\nthe queue.\n\n### Design Issues\n\nPython\'s queue also does not provide much help for common tasks that queues\nare used for, such as a list of work for _Producer/Consumer_ design patterns.\nPython\'s own `queue` documentation shows the following\n[example](https://docs.python.org/3/library/queue.html#queue.Queue.join):\n```python\nimport threading, queue\n\nq = queue.Queue()\n\ndef worker():\n    while True:\n        item = q.get()\n        print(f\'Working on {item}\')\n        print(f\'Finished {item}\')\n        q.task_done()\n\n# turn-on the worker thread\nthreading.Thread(target=worker, daemon=True).start()\n\n# send thirty task requests to the worker\nfor item in range(30):\n    q.put(item)\nprint(\'All task requests sent\\n\', end=\'\')\n\n# block until all tasks are done\nq.join()\nprint(\'All work completed\')\n```\nEven here in the official docs, there are problems. They\'ve omitted the\nnecessary exception handling; if the worker were to raise an exception between\n`q.get()` and `q.task_done()`, the call to `q.join()` might block indefinitely.\n(Yes, `print()` is not likely to raise an exception, but real work done by such\na queue _is_...)\nThis can be fixed by adding try/finally, but the semantics are subtle and as\nthis example shows, error-prone.\n\nThe example also does not actually terminate the consumer thread correctly and\ninstead just lets it die as a daemon thread. This might be okay for an example,\nbut this is not good for realistic uses of the queue where resources need\nstricter management. This is doubly ironic, because the point of `q.join()` is\nto (presumably) support _draining_ the queue and block until the queue is\nempty. However, any logic to handle basic draining requires more tooling that\nis outside of the queue (i.e. checking some `threading.Event` instead of\n`while True`), thus (in my opinion) defeating the point. This situation is\nfurther complicated by the situation below:\n```python\nimport queue\n\nq = queue.Queue()\nq.put(\'a\')\n\ndef consumer():\n    q.get()\n    # Uh-oh. No timeout argument passed, so this blocks indefinitely.\n    # Ctrl+C to get out of this, or worse (!) since some versions of python\n    # did not even support Ctrl+C in this setting...\n    q.get()\n\nconsumer()\n```\nThe consumer might be blocked waiting for an element before it has a chance to\ncheck whether the stop event was set.\n\n### Better Design\n\nThe necessary variables to handle the draining should already implicitly be\navailable in the queue object, with improved calls. The queue should have some\n`stop()` call that stops the queue and wakes up anyone waiting indefinitely to\ninsert/remove an item with a `QueueStopped()` exception or similar to avoid\ndeadlock.\n\nAdding pythonic generators to remove items from the queue can also help with\nthese common cases; the consumer can simply iterate to obtain the next item\ninstead of handling the complicated `pop/get` logic that might otherwise be\nrequired.\n\nThis is all provided by `bufferq.Queue` like below:\n```python\nimport threading\nimport bufferq\n\nq = bufferq.Queue()\ndef worker():\n\tfor item in q.consume_one_generator():\n        print(f\'Working on {item}\')\n        print(f\'Finished {item}\')\n\n# turn-on the worker thread\nthd = threading.Thread(target=worker, daemon=True).start()\n\n# send thirty task requests to the worker\nfor item in range(30):\n    q.put(item)\nprint(\'All task requests sent, signal to stop and drain.\')\n# Request that the queue stop, since everything has been added.\nq.stop()\n\nthd.join()\nprint(\'All work completed and workers joined!\')\n```\n',
    'author': 'Aaron Gibson',
    'author_email': 'eulersidcrisis@yahoo.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/eulersIDcrisis/bufferq',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
