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

package_dir = \
{'': 'src'}

packages = \
['aqueue']

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

install_requires = \
['attrs>=22.1.0,<23.0.0', 'rich>=12.6.0,<13.0.0', 'trio>=0.22.0,<0.23.0']

setup_kwargs = {
    'name': 'aqueue',
    'version': '0.3.2',
    'description': 'An async queue with live progress display',
    'long_description': '# aqueue\n\n![demo](docs/demo.gif)\n\nAn async queue with live progress display. Good for running and visualizing tree-like I/O-bound\nprocessing jobs, such as website scrapes.\n\n## Example\n\n```python\nimport random\nfrom typing import ClassVar\n\nimport trio\n\nfrom aqueue import EnqueueFn, Item, SetDescFn, run_queue\n\n\nclass RootItem(Item):\n    async def process(self, enqueue: EnqueueFn, set_desc: SetDescFn) -> None:\n        # display what we\'re doing in the worker status panel\n        set_desc("Making child items")\n\n        for _ in range(3):\n            # simulate doing work and creating more items\n            await trio.sleep(random.random())\n            enqueue(ChildItem())\n\n    async def after_children_processed(self) -> None:\n        print("All done!")\n\n\nclass ChildItem(Item):\n    # track these items on the Overall Progress panel\n    track_overall: ClassVar[bool] = True\n\n    async def process(self, enqueue: EnqueueFn, set_desc: SetDescFn) -> None:\n        set_desc("Doing work...")\n\n        # Simulate doing work\n        await trio.sleep(random.random())\n\n\ndef main() -> None:\n    run_queue(\n        initial_items=[RootItem()],\n        num_workers=2,\n    )\n\n\nif __name__ == "__main__":\n    main()\n\n```\n\n## Installation\n\n```shell\npip install aqueue\n```\n\n## Usage Notes\n\nThere\'s two things you need to do to use aqueue:\n\n1. Write your [Item](#items) classes\n2. [Start your queue](#starting-your-queue) with one of those items\n\n### Items\n\nItems are your units of work. They can represent whatever you\'d like, such as parts of a website\nthat you\'re trying to scrape: an item for the index page, for subpages, for images, etc.\n\nEach item should be an instance of a class. It\'s not required, but subclassing from `aqueue.Item`\nmay let your editor give you better assistance.\n\nFor example:\n\n```python\nfrom typing import ClassVar\nimport aqueue\n\nclass MyItem(aqueue.Item):\n    async def process(self, enqueue: aqueue.EnqueueFn, set_desc: aqueue.SetDescFn) -> None:\n        # display what we\'re doing in the worker status panel\n        set_desc(\'Processing MyItem\')\n\n        # make an HTTP request, parse it, etc\n        ...\n\n        # when you discover more items you want to process, enqueue them:\n        enqueue(AnotherItem())\n\nclass AnotherItem(aqueue.Item):\n\n    track_overall: ClassVar[bool] = True\n\n    async def process(self, enqueue: aqueue.EnqueueFn, set_desc: aqueue.SetDescFn) -> None:\n        set_desc(\'Processing AnotherItem\')\n```\n\nAs a rule of thumb, you should make a new item class whenever you notice a one-to-many relationship.\nFor example, this _one_ page has _many_ images I want to download.\n\nNote: `process` is async, but because this library uses\n[Trio](https://trio.readthedocs.io/en/stable/index.html) under the hood, you may only use\nTrio-compatible primitives inside `process`. For example, use `trio.sleep`, not `asyncio.sleep`.\nTODO: consider [AnyIO](https://anyio.readthedocs.io/en/stable/) to avoid this problem?\n\nDisclaimer: aqueue, or any asynchronous framework, is only going to be helpful if you\'re performing\nwork is I/O-bound.\n\n#### `process` method, required\n\nAn item class must define an async `process` method. As arguments, it should accept two positional arguments:\n\n1. a `aqueue.EnqueueFn` that can be called to enqueue more work. That type is simply an alias for\n   `Callable[[Item], None]`.\n2. a `aqueue.SetDescFn` that can be called to update this worker\'s status with a string description.\n\n#### `after_children_processed` method, optional\n\nYou can implement an `after_children_processed` method. After this item\'s `process` and any\n(recursive) child\'s `process` are called, this method will be called.\n\n#### `track_overall` property, optional\n\nIf set to True, when this item is enqueued, the Overall Progress total count increments. After its\nprocess method completed, the Overall Progress completed count increments\n\n### Starting your Queue\n\nThen, start your queue with an initial item(s) to kick things off.\n\n```python\naqueue.run_queue(\n    initial_items=[MyItem()],\n    num_workers=2,\n    queue_type_name="stack",\n    graceful_ctrl_c=True,\n)\n```\n\n#### Queue type\n\nBy default, the queue is actually ...a queue -- that is to say that items are processed\nfirst-in-first-out. Here are all the types you can specify with the `queue_type_name` argument.\n\n- `queue` - first-in-first-out processing, or breadth-first.\n- `stack` - last-in-first-out processing, or depth-first. This one is recommended for website\n  scraping because it yields items fast (versus `queue` that tries to look at all the intermediate\n  pages first).\n- `priority` - priority queue processing. In this case, your item objects should be orderable (with\n  `__lt__`, etc). **Lesser objects will be processed first**, because this code uses a minheap.\n\n#### Number of workers\n\nYou can specify the number of workers you\'d like to be processing your items with the `num_workers`\nargument.\n\n#### Ctrl-C\n\nIf you decide you want to stop your queue processing, press Ctrl-C.\n\nIf you\'ve set the `graceful_ctrl_c` to False, this will stop the program immediately. If True, the\ndefault, aqueue will wait for the items currently being worked on to complete (without taking any\nadditional items), and _then_ stop. Put another way, the choice is between responsiveness and\nresource consistency.\n\n### Sharing state\n\nOften, its beneficial to share state between the items. Using the website scrape example again, you\nmay want to keep track of the URLs you\'ve visited so you don\'t scrape them twice.\n\nIf this is needed, simply keep a global set/dict/list and store a key for the item. For example, a\nURL string may be a good key.\n\nIf you don\'t want to or can\'t use a global variable, consider a\n[`ContextVar`](https://docs.python.org/3/library/contextvars.html).\n\n### Persisting state\n\nDuring development, its probably likely that your program will crash after doing some work. For\nexample, maybe your HTTP request timed out or you had a bug in your HTML parsing.\n\nIt\'s a shame to lose that work that\'s been done. So, if you\'re looking for a really handy way to\npersist state across runs, check out the built-in\n[`shelve`](https://docs.python.org/3/library/shelve.html) module. It\'s like a dict that\nautomatically saves to a file each time you set a key in it.\n\n### Other cool things\n\nThe API is fully docstringed and type-hinted 🥳\n',
    'author': 'Tim Martin',
    'author_email': 'tim@timmart.in',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'None',
    'package_dir': package_dir,
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.10,<4.0',
}


setup(**setup_kwargs)
