{ "info": { "author": "Florimond Manca", "author_email": "florimond.manca@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 1 - Planning", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# aiodine\n\n[![python](https://img.shields.io/pypi/pyversions/aiodine.svg?logo=python&logoColor=fed749&colorB=3770a0&label=)](https://www.python.org)\n[![pypi](https://img.shields.io/pypi/v/aiodine.svg)][pypi-url]\n[![travis](https://img.shields.io/travis/bocadilloproject/aiodine.svg)](https://travis-ci.org/bocadilloproject/aiodine)\n[![black](https://img.shields.io/badge/code_style-black-000000.svg)](https://github.com/ambv/black)\n[![codecov](https://codecov.io/gh/bocadilloproject/aiodine/branch/master/graph/badge.svg)](https://codecov.io/gh/bocadilloproject/aiodine)\n[![license](https://img.shields.io/pypi/l/aiodine.svg)][pypi-url]\n\n[pypi-url]: https://pypi.org/project/aiodine/\n\naiodine provides async-first [dependency injection][di] in the style of [Pytest fixtures](https://docs.pytest.org/en/latest/fixture.html) for Python 3.6+.\n\n- [Installation](#installation)\n- [Concepts](#concepts)\n- [Usage](#usage)\n- [FAQ](#faq)\n- [Changelog](#changelog)\n\n## Installation\n\n```bash\npip install \"aiodine==1.*\"\n```\n\n## Concepts\n\naiodine revolves around two concepts:\n\n- **Providers** are in charge of setting up, returning and optionally cleaning up _resources_.\n- **Consumers** can access these resources by declaring the provider as one of their parameters.\n\nThis approach is an implementation of [Dependency Injection][di] and makes providers and consumers:\n\n- **Explicit**: referencing providers by name on the consumer's signature makes dependencies clear and predictable.\n- **Modular**: a provider can itself consume other providers, allowing to build ecosystems of reusable (and replaceable) dependencies.\n- **Flexible**: provided values are reused within a given scope, and providers and consumers support a variety of syntaxes (asynchronous/synchronous, function/generator) to make provisioning fun again.\n\naiodine is **async-first** in the sense that:\n\n- It was made to work with coroutine functions and the async/await syntax.\n- Consumers can only be called in an asynchronous setting.\n- But provider and consumer functions can be regular Python functions and generators too, if only for convenience.\n\n## Usage\n\n### Providers\n\n**Providers** make a _resource_ available to consumers within a certain _scope_. They are created by decorating a **provider function** with `@aiodine.provider`.\n\nHere's a \"hello world\" provider:\n\n```python\nimport aiodine\n\n@aiodine.provider\nasync def hello():\n return \"Hello, aiodine!\"\n```\n\nProviders are available in two **scopes**:\n\n- `function`: the provider's value is re-computed everytime it is consumed.\n- `session`: the provider's value is computed only once (the first time it is consumed) and is reused in subsequent calls.\n\nBy default, providers are function-scoped.\n\n### Consumers\n\nOnce a provider has been declared, it can be used by **consumers**. A consumer is built by decorating a **consumer function** with `@aiodine.consumer`. A consumer can declare a provider as one of its parameters and aiodine will inject it at runtime.\n\nHere's an example consumer:\n\n```python\n@aiodine.consumer\nasync def show_friendly_message(hello):\n print(hello)\n```\n\nAll aiodine consumers are asynchronous, so you'll need to run them in an asynchronous context:\n\n```python\nfrom asyncio import run\n\nasync def main():\n await show_friendly_message()\n\nrun(main()) # \"Hello, aiodine!\"\n```\n\nOf course, a consumer can declare non-provider parameters too. aiodine is smart enough to figure out which parameters should be injected via providers, and which should be expected from the callee.\n\n```python\n@aiodine.consumer\nasync def show_friendly_message(hello, repeat=1):\n for _ in range(repeat):\n print(hello)\n\nasync def main():\n await show_friendly_message(repeat=10)\n```\n\n### Providers consuming other providers\n\nProviders are modular in the sense that they can themselves consume other providers.\n\nFor this to work however, providers need to be **frozen** first. This ensures that the dependency graph is correctly resolved regardless of the declaration order.\n\n```python\nimport aiodine\n\n@aiodine.provider\ndef email():\n return \"user@example.net\"\n\n@aiodine.provider\nasync def send_email(email):\n print(f\"Sending email to {email}\u2026\")\n\naiodine.freeze() # <- Ensures that `send_email` has resolved `email`.\n```\n\n**Note**: it is safe to call `.freeze()` multiple times.\n\nA context manager syntax is also available:\n\n```python\nimport aiodine\n\nwith aiodine.exit_freeze():\n @aiodine.provider\n def email():\n return \"user@example.net\"\n\n @aiodine.provider\n async def send_email(email):\n print(f\"Sending email to {email}\u2026\")\n```\n\n### Generator providers\n\nGenerator providers can be used to perform cleanup (finalization) operations after a provider has gone out of scope.\n\n```python\nimport os\nimport aiodine\n\n@aiodine.provider\nasync def complex_resource():\n print(\"setting up complex resource\u2026\")\n yield \"complex\"\n print(\"cleaning up complex resource\u2026\")\n```\n\n**Tip**: cleanup code is executed even if an exception occurred in the consumer, so there's no need to surround the `yield` statement with a `try/finally` block.\n\n**Important**: session-scoped generator providers will only be cleaned up if using them in the context of a session. See [Sessions](#sessions) for details.\n\n### Lazy async providers\n\nAsync providers are **eager** by default: their return value is awaited before being injected into the consumer.\n\nYou can mark a provider as **lazy** in order to defer awaiting the provided value to the consumer. This is useful when the provider needs to be conditionally evaluated.\n\n```python\nfrom asyncio import sleep\nimport aiodine\n\n@aiodine.provider(lazy=True)\nasync def expensive_io_call():\n await sleep(10)\n return 42\n\n@aiodine.consumer\nasync def compute(expensive_io_call, cache=None):\n if cache:\n return cache\n return await expensive_io_call\n```\n\n### Factory providers\n\nInstead of returning a scalar value, factory providers return a _function_. Factory providers are useful to implement reusable providers that accept a variety of inputs.\n\n> This is a _design pattern_ more than anything else. In fact, there's no extra code in aiodine to support this feature.\n\nThe following example defines a factory provider for a (simulated) database query:\n\n```python\nimport aiodine\n\n@aiodine.provider(scope=\"session\")\nasync def notes():\n # Some hard-coded sticky notes.\n return [\n {\"id\": 1, \"text\": \"Groceries\"},\n {\"id\": 2, \"text\": \"Make potatoe smash\"},\n ]\n\n@aiodine.provider\nasync def get_note(notes):\n async def _get_note(pk: int) -> list:\n try:\n # TODO: fetch from a database instead?\n return next(note for note in notes if note[\"id\"] == pk)\n except StopIteration:\n raise ValueError(f\"Note with ID {pk} does not exist.\")\n\n return _get_note\n```\n\nExample usage in a consumer:\n\n```python\n@aiodine.consumer\nasync def show_note(pk: int, get_note):\n print(await get_note(pk))\n```\n\n**Tip**: you can combine factory providers with [generator providers](#generator-providers) to cleanup any resources the factory needs to use. Here's an example that provides temporary files and removes them on cleanup:\n\n```python\nimport os\nimport aiodine\n\n@aiodine.provider(scope=\"session\")\ndef tmpfile():\n files = set()\n\n async def _create_tmpfile(path: str):\n with open(path, \"w\") as tmp:\n files.add(path)\n return tmp\n\n yield _create_tmpfile\n\n for path in files:\n os.remove(path)\n```\n\n### Using providers without declaring them as parameters\n\nSometimes, a consumer needs to use a provider but doesn't care about the value it returns. In these situations, you can use the `@useprovider` decorator and skip declaring it as a parameter.\n\n**Tip**: the `@useprovider` decorator accepts a variable number of providers, which can be given by name or by reference.\n\n```python\nimport os\nimport aiodine\n\n@aiodine.provider\ndef cache():\n os.makedirs(\"cache\", exist_ok=True)\n\n@aiodine.provider\ndef debug_log_file():\n with open(\"debug.log\", \"w\"):\n pass\n yield\n os.remove(\"debug.log\")\n\n@aiodine.consumer\n@aiodine.useprovider(\"cache\", debug_log_file)\nasync def build_index():\n ...\n```\n\n### Auto-used providers\n\nAuto-used providers are **automatically activated** (within their configured scope) without having to declare them as a parameter in the consumer.\n\nThis can typically spare you from decorating all your consumers with an `@useprovider`.\n\nFor example, the auto-used provider below would result in printing the current date and time to the console every time a consumer is called.\n\n```python\nimport datetime\nimport aiodine\n\n@aiodine.provider(autouse=True)\nasync def logdatetime():\n print(datetime.now())\n```\n\n### Sessions\n\nA **session** is the context in which _session providers_ live.\n\nMore specifically, session providers (resp. generator session providers) are instanciated (resp. setup) when entering a session, and destroyed (resp. cleaned up) when exiting the session.\n\nTo enter a session, use:\n\n```python\nawait aiodine.enter_session()\n```\n\nTo exit it:\n\n```python\nawait aiodine.exit_session()\n```\n\nAn async context manager syntax is also available:\n\n```python\nasync with aiodine.session():\n ...\n```\n\n### Context providers\n\n> **WARNING**: this is an experimental feature.\n\nContext providers were introduced to solve the problem of injecting **context-local resources**. These resources are typically undefined at the time of provider declaration, but become well-defined when entering some kind of **context**.\n\nThis may sound abstract, so let's see an example before showing the usage of context providers.\n\n#### Example\n\nLet's say we're in a restaurant. There, a waiter executes orders submitted by customers. Each customer is given an `Order` object which they can `.write()` their desired menu items to.\n\nIn aiodine terminilogy, the waiter is the [provider](#providers) of the order, and the customer is a [consumer](#consumers).\n\nDuring service, the waiter needs to listen to new customers, create a new `Order` object, provide it to the customer, execute the order as written by the customer, and destroy the executed order.\n\nSo, in this example, the **context** spans from when an order is created to when it is destroyed, and is specific to a given customer.\n\nHere's what code simulating this situation on the waiter's side may look like:\n\n```python\nfrom asyncio import Queue\n\nimport aiodine\n\nclass Order:\n def write(self, item: str):\n ...\n\nclass Waiter:\n def __init__(self):\n self._order = None\n self.queue = Queue()\n\n # Create an `order` provider for customers to use.\n # NOTE: the actually provided value is not defined yet!\n @aiodine.provider\n def order():\n return self._order\n\n async def _execute(self, order: Order):\n ...\n\n async def _serve(self, customer):\n # NOTE: we've now entered the *context* of serving\n # a particular customer.\n\n # Create a new order that the customer can\n # via the `order` provider.\n self._order = Order()\n\n await customer()\n\n # Execute the order and destroy it.\n await self._execute(self._order)\n self._order = None\n\n async def start(self):\n while True:\n customer = await self.queue.get()\n await self._serve(customer)\n```\n\nIt's important to note that customers can do _anything_ with the order. In particular, they may take some time to think about what they are going to order. In the meantime, the server will be listening to other customer calls. In this sense, this situation is an _asynchronous_ one.\n\nAn example customer code may look like this:\n\n```python\nfrom asyncio import sleep\n\n@aiodine.consumer\ndef alice(order: Order):\n # Pondering while looking at the menu\u2026\n await sleep(10)\n order.write(\"Pizza Margheritta\")\n```\n\nLet's reflect on this for a second. Have you noticed that the waiter holds only _one_ reference to an `Order`? This means that the code works fine as long as only _one_ customer is served at a time.\n\nBut what if another customer, say `bob`, comes along while `alice` is thinking about what she'll order? With the current implementation, the waiter will simply _forget_ about `alice`'s order, and end up executing `bob`'s order twice. In short: we'll encounter a **race condition**.\n\nBy using a context provider, we transparently turn the waiter's `order` into a [context variable][contextvars] (a.k.a. `ContextVar`). It is local to the context of each customer, which solves the race condition.\n\n[contextvars]: https://docs.python.org/3/library/contextvars.html\n\nHere's how the code would then look like:\n\n```python\nimport aiodine\n\nclass Waiter:\n def __init__(self):\n self.queue = Queue()\n self.provider = aiodine.create_context_provider(\"order\")\n\n async def _execute(self, order: Order):\n ...\n\n async def _serve(self, customer):\n order = Order()\n with self.provider.assign(order=order):\n await customer()\n await self._execute(order)\n\n async def start(self):\n while True:\n customer = await self.queue.get()\n await self._serve(customer)\n```\n\nNote:\n\n- Customers can use the `order` provider just like before. In fact, it was created when calling `.create_context_provider()`.\n- The `order` is now **context-local**, i.e. its value won't be forgotten or scrambled if other customers come and make orders concurrently.\n\nThis situation may look trivial to some, but it is likely to be found in client/server architectures, including in web frameworks.\n\n#### Usage\n\nTo create a context provider, use `aiodine.create_context_provider()`. This method accepts a variable number of arguments and returns a `ContextProvider`. Each argument is used as the name of a new [`@provider`](#providers) which provides the contents of a [`ContextVar`][contextvars] object.\n\n```python\nimport aiodine\n\nprovider = aiodine.create_context_provider(\"first_name\", \"last_name\")\n```\n\nEach context variable contains `None` initially. This means that consumers will receive `None` \u2014 unless they are called within the context of an `.assign()` block:\n\n```python\nwith provider.assign(first_name=\"alice\"):\n # Consumers called in this block will receive `\"alice\"`\n # if they consume the `first_name` provider.\n ...\n```\n\n## FAQ\n\n### Why \"aiodine\"?\n\naiodine contains \"aio\" as in [asyncio], and \"di\" as in [Dependency Injection][di]. The last two letters end up making aiodine pronounce like [iodine], the chemical element.\n\n[asyncio]: https://docs.python.org/3/library/asyncio.html\n[di]: https://en.wikipedia.org/wiki/Dependency_injection\n[iodine]: https://en.wikipedia.org/wiki/Iodine\n\n## Changelog\n\nSee [CHANGELOG.md](https://github.com/bocadilloproject/aiodine/blob/master/CHANGELOG.md).\n\n## License\n\nMIT\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/bocadilloproject/aiodine", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "aiodine", "package_url": "https://pypi.org/project/aiodine/", "platform": "", "project_url": "https://pypi.org/project/aiodine/", "project_urls": { "Homepage": "https://github.com/bocadilloproject/aiodine" }, "release_url": "https://pypi.org/project/aiodine/1.2.9/", "requires_dist": [ "async-exit-stack ; python_version < \"3.7\"", "aiocontextvars ; python_version < \"3.7\"" ], "requires_python": ">=3.6", "summary": "Async-first dependency injection library for Python", "version": "1.2.9" }, "last_serial": 5975403, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "0062d525a2c57c7dea97e83e16c548fb", "sha256": "feeb50df4d8a5bcce8571509c9620439d8d2792befd287959ab34492e945bf6d" }, "downloads": -1, "filename": "aiodine-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "0062d525a2c57c7dea97e83e16c548fb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13498, "upload_time": "2019-02-28T00:02:36", "url": "https://files.pythonhosted.org/packages/d0/c7/e74842f61315de6f3e988ac669887be386fbd0eb7083ee47831eb9f03456/aiodine-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6a64ea529611198eaf428cc2a78bbde3", "sha256": "1b7811dfb0ee893bbf4b4f0f112ceff02224a6530c53664f31fec98af25181a4" }, "downloads": -1, "filename": "aiodine-0.1.0.tar.gz", "has_sig": false, "md5_digest": "6a64ea529611198eaf428cc2a78bbde3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10152, "upload_time": "2019-02-28T00:02:38", "url": "https://files.pythonhosted.org/packages/1a/2a/55ca3a1ff2a82b63cec7cf5b70f2dab2fd11cb477d878a08ed6fffd1fd37/aiodine-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "9f75be698b12120cf783d682d9eef8fd", "sha256": "d2ab6840fe00666b797a1398ff5d17276d857ed77487df86daee1d8002fbcb0a" }, "downloads": -1, "filename": "aiodine-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "9f75be698b12120cf783d682d9eef8fd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14082, "upload_time": "2019-02-28T20:14:38", "url": "https://files.pythonhosted.org/packages/bb/aa/d547738f401eccd480fcbf6febfa868881a550a3f6d8625aaace8a026b77/aiodine-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c234a0bc4e1b695e939e13613111b0fc", "sha256": "9b896effa60363c59bcb4ffb6e29ce69a5af279e6216fca7713c7fa2124bd33c" }, "downloads": -1, "filename": "aiodine-0.1.1.tar.gz", "has_sig": false, "md5_digest": "c234a0bc4e1b695e939e13613111b0fc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10829, "upload_time": "2019-02-28T20:14:40", "url": "https://files.pythonhosted.org/packages/11/f7/8a3d22ea3ba4643685c58d1f6bfa534ee55aca45c48dbfbac6b2f59b2981/aiodine-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "3f46a66746c668e259438b39284893fd", "sha256": "9b9cda5598dbb9ad476010460d751beb548ce63e72cde626d02b2cca585b54d1" }, "downloads": -1, "filename": "aiodine-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "3f46a66746c668e259438b39284893fd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14177, "upload_time": "2019-02-28T21:40:59", "url": "https://files.pythonhosted.org/packages/8c/61/ab50f077e3d4f45d566c25078218940b64b7f515874759e7f96db7bf4881/aiodine-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7207eaaff8f3dbd576fde72ded02ce44", "sha256": "5bf7cfa502d26085220c697ce9366aa9ea6d9960368f33a53b5bd4e1e8058553" }, "downloads": -1, "filename": "aiodine-0.1.2.tar.gz", "has_sig": false, "md5_digest": "7207eaaff8f3dbd576fde72ded02ce44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10896, "upload_time": "2019-02-28T21:41:01", "url": "https://files.pythonhosted.org/packages/8e/81/8480bf65b4fab27a9f8797bc15bbab63a7b8c41b6ecee0d266c59e936908/aiodine-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "591697220180380e1e6e3ac4d2de8b01", "sha256": "dda1d99bd34438cdef7a958f413fca795b1e26f159f39ce3b16c07088b787cc7" }, "downloads": -1, "filename": "aiodine-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "591697220180380e1e6e3ac4d2de8b01", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14122, "upload_time": "2019-03-01T08:32:03", "url": "https://files.pythonhosted.org/packages/09/65/14defe01c7680b114bf5cbe7dafe85d55dade2c3bbc03520254719264a14/aiodine-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "85a2d437b23163fd70ee56f861943d76", "sha256": "1b4ceff63341536eaaa933626866e7a856e7a465fc3f415b9cd62b1601e2b260" }, "downloads": -1, "filename": "aiodine-0.1.3.tar.gz", "has_sig": false, "md5_digest": "85a2d437b23163fd70ee56f861943d76", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10883, "upload_time": "2019-03-01T08:32:04", "url": "https://files.pythonhosted.org/packages/97/2d/2a2cf977b6a2fed730a6254086f6c153b8d0cbff5915aa43079bdc1a3674/aiodine-0.1.3.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "66303c44d26acfc6ff7aad68e4715515", "sha256": "a5d8aeb115b59ef9f373b23ec82e269e1bec847890d9a34962b2bf92cb52a852" }, "downloads": -1, "filename": "aiodine-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "66303c44d26acfc6ff7aad68e4715515", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15787, "upload_time": "2019-03-02T16:26:16", "url": "https://files.pythonhosted.org/packages/e6/63/35fdaad653705a2511b1c84a3b286683b851c68f1dd04bbd26bb0763c6a4/aiodine-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2aa03a715ecaa64d2eb30edb1fa1592e", "sha256": "7c8156241ccfb1826e8c7fa34e03345d7b7e853368a944fd9b094017c44df12f" }, "downloads": -1, "filename": "aiodine-0.2.0.tar.gz", "has_sig": false, "md5_digest": "2aa03a715ecaa64d2eb30edb1fa1592e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13016, "upload_time": "2019-03-02T16:26:17", "url": "https://files.pythonhosted.org/packages/17/46/03662ca3493e77cf5ad15ef329d8731af647780316bd5176d7cb44115ef4/aiodine-0.2.0.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "0357fa2c2e72243afbe9cb11c601982f", "sha256": "4d3ef6d7f7fc54c6930a750c27ed3316b3ba112564c4414a4100961a36d76f96" }, "downloads": -1, "filename": "aiodine-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "0357fa2c2e72243afbe9cb11c601982f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 17713, "upload_time": "2019-03-03T00:24:13", "url": "https://files.pythonhosted.org/packages/ac/87/c87af51ff17930d3552aba5fa9d86005657127c8feb31854ed05253e08bb/aiodine-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "eb22d42cf7fabbb10c6b3c635afa9566", "sha256": "3f019e243cb410307b820bf404bcaf477409ed1c1de80fc6704f8de4867154a7" }, "downloads": -1, "filename": "aiodine-1.0.0.tar.gz", "has_sig": false, "md5_digest": "eb22d42cf7fabbb10c6b3c635afa9566", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 14604, "upload_time": "2019-03-03T00:24:14", "url": "https://files.pythonhosted.org/packages/4e/e3/e9b58c0241598a1ea3f1a345301a4c10237baf15df36a80c111d43526b88/aiodine-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "cc3c8f23a7da38ffbc49b908a4ec8445", "sha256": "a4e034f8d685d6afb60aead576364f75c9d9a561eedd4aeea07f1437304dbd67" }, "downloads": -1, "filename": "aiodine-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "cc3c8f23a7da38ffbc49b908a4ec8445", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 18088, "upload_time": "2019-03-03T01:01:38", "url": "https://files.pythonhosted.org/packages/5c/9b/b12fa9f1bf98faee90ef25f552a633be8baaff5a8e0335af27f43c8fe807/aiodine-1.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b35728337ef2be15dc14ad8f35c8843e", "sha256": "084f706e0295717bd51124f34415f39763cb5feda2759b85ea49f3ecd7f12093" }, "downloads": -1, "filename": "aiodine-1.0.1.tar.gz", "has_sig": false, "md5_digest": "b35728337ef2be15dc14ad8f35c8843e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 15331, "upload_time": "2019-03-03T01:01:39", "url": "https://files.pythonhosted.org/packages/30/da/640031b2f39e3bdac50857878d1cf348a2e95d87da160c989abdeeeb52da/aiodine-1.0.1.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "64c1c6a57737f45a2211141188c2e4e7", "sha256": "433c71d9265cdb93535465c3fde954ed05ca94f9167d565251fc55ee6fd14263" }, "downloads": -1, "filename": "aiodine-1.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "64c1c6a57737f45a2211141188c2e4e7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 21138, "upload_time": "2019-03-09T10:27:26", "url": "https://files.pythonhosted.org/packages/60/6e/3bf9d11dea0401265447400d7d246f2d5526eceaf8644bd4788b569dc45f/aiodine-1.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4406564cafd14f35d7bf146b6eb43c17", "sha256": "7af4fc6e87f86a1f8786efe99d2d199e81f24ede9f230608cb5d5bdfb9e7fc41" }, "downloads": -1, "filename": "aiodine-1.1.0.tar.gz", "has_sig": false, "md5_digest": "4406564cafd14f35d7bf146b6eb43c17", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 19593, "upload_time": "2019-03-09T10:27:27", "url": "https://files.pythonhosted.org/packages/01/36/60280d17fad2cf74093139382e47c398a6b3b767a0543a1f47dffabc1be8/aiodine-1.1.0.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "e1cde175fb28e70250f2b27b60ea5b7b", "sha256": "2fe2b775a0f1e082caeba43fd9abf353f74f557816de22d6f29fcbcc3adc3e3e" }, "downloads": -1, "filename": "aiodine-1.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "e1cde175fb28e70250f2b27b60ea5b7b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 21170, "upload_time": "2019-03-14T14:40:53", "url": "https://files.pythonhosted.org/packages/1a/67/28385e8d8e56169447ffbf08f050899b0e7678842605fac22f30dde07bda/aiodine-1.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4eaee738b0b9c73bdb126f17a2392afb", "sha256": "6913e70738221e09d43c5c188c32fcc73009522fe4edca117d1b1883f96dfc19" }, "downloads": -1, "filename": "aiodine-1.1.1.tar.gz", "has_sig": false, "md5_digest": "4eaee738b0b9c73bdb126f17a2392afb", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 19618, "upload_time": "2019-03-14T14:40:55", "url": "https://files.pythonhosted.org/packages/2c/63/63bf56c841c853e6e4339e4b5d3027b4d9345cb4d566190027f679a807c6/aiodine-1.1.1.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "faed90c9c3f8e0f65955811043d16e2d", "sha256": "3e78004dd8d202fb46a8b9f72a9c6cd44b8d568a9cb28ff6e94e2e0617fe0dc0" }, "downloads": -1, "filename": "aiodine-1.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "faed90c9c3f8e0f65955811043d16e2d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 22708, "upload_time": "2019-03-15T21:07:16", "url": "https://files.pythonhosted.org/packages/2b/51/b45c60e814317395e4929d873faf6ef756f1e3ecfd72ee3b3b036018dbda/aiodine-1.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e72757fa118e613d27cf3186c86ae7b1", "sha256": "05f69fa4e376da4b1273932644afe35fd01a0f476f110808b1a265a20dcd111d" }, "downloads": -1, "filename": "aiodine-1.2.0.tar.gz", "has_sig": false, "md5_digest": "e72757fa118e613d27cf3186c86ae7b1", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20144, "upload_time": "2019-03-15T21:07:17", "url": "https://files.pythonhosted.org/packages/ca/a6/daec59ec1b3de69b9bff0e04c2351cd1473123720f043279a425fb351f40/aiodine-1.2.0.tar.gz" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "4685f7769486213aae496b9abf61168a", "sha256": "fe1158690f7909c9b82704af3802da2b776cf08e1a38051105fb1cecfc6c347b" }, "downloads": -1, "filename": "aiodine-1.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "4685f7769486213aae496b9abf61168a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 22821, "upload_time": "2019-03-15T22:13:42", "url": "https://files.pythonhosted.org/packages/90/04/4d43f74c0171df1fb43940371ace8c1e8a3295eeb02e90e717f6e94340a5/aiodine-1.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "02bdb30b85d012d9408f1870b9fb62b7", "sha256": "017fa624eed80cc82c7bd161087691ebe2c41af8e3b6a24b562e6abcb376e75f" }, "downloads": -1, "filename": "aiodine-1.2.1.tar.gz", "has_sig": false, "md5_digest": "02bdb30b85d012d9408f1870b9fb62b7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20232, "upload_time": "2019-03-15T22:13:44", "url": "https://files.pythonhosted.org/packages/8f/22/2e98d7eb9ff126e6fbd52e2242cd0cf539c29e83d41400f0446189b03861/aiodine-1.2.1.tar.gz" } ], "1.2.2": [ { "comment_text": "", "digests": { "md5": "0f2199ae03904edc76bfc15d5098e182", "sha256": "5da565caf649dd30c0b13060f63a4192efbb42838ce3544347548b297d68aa41" }, "downloads": -1, "filename": "aiodine-1.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "0f2199ae03904edc76bfc15d5098e182", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 22860, "upload_time": "2019-03-24T12:53:07", "url": "https://files.pythonhosted.org/packages/46/fa/c014fda08e7aa9ac24b5975e3872d24983cc22722653bff9b6ce10a34fea/aiodine-1.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fc0e860f5176c98a17ef6a79f5157e06", "sha256": "595826b921adc4d85cdb349097e7f529bd9ebd506e80a8ab5af91920a6159f11" }, "downloads": -1, "filename": "aiodine-1.2.2.tar.gz", "has_sig": false, "md5_digest": "fc0e860f5176c98a17ef6a79f5157e06", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20285, "upload_time": "2019-03-24T12:53:08", "url": "https://files.pythonhosted.org/packages/bd/8d/af90d7253ffa2e8c63324dbc8a53753f42a0804b63cbad67f741dc35d395/aiodine-1.2.2.tar.gz" } ], "1.2.3": [ { "comment_text": "", "digests": { "md5": "ddae0bc5b0e7e2641f8a2cd41fa802ea", "sha256": "ddf9377dfc8158302d2306b41d651ebfa4dabc4e390052579c9d1d5a4c74e3ea" }, "downloads": -1, "filename": "aiodine-1.2.3-py3-none-any.whl", "has_sig": false, "md5_digest": "ddae0bc5b0e7e2641f8a2cd41fa802ea", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 22910, "upload_time": "2019-03-29T22:46:40", "url": "https://files.pythonhosted.org/packages/26/04/be91de4330c824ab23f0dbf67bcbd6068cbfea247da324beeefe3324b418/aiodine-1.2.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "da69119607137e91b733d869bad7d83c", "sha256": "5aa0e6c63f1b7279c02d4619c2e92a72ad3fa8a337d5bacb53f9fc584eca02a1" }, "downloads": -1, "filename": "aiodine-1.2.3.tar.gz", "has_sig": false, "md5_digest": "da69119607137e91b733d869bad7d83c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20322, "upload_time": "2019-03-29T22:46:41", "url": "https://files.pythonhosted.org/packages/d1/d6/040af9571f2a0dd189b7c14b68696f023122b8bb2fd9731b1e8db409d3aa/aiodine-1.2.3.tar.gz" } ], "1.2.4": [ { "comment_text": "", "digests": { "md5": "2d113f10d055a96ef3dd33c95cfc1fbc", "sha256": "9c1ff5d56358cf7b33409fa9d752b4589e508ac19bb3be72876a840d41835293" }, "downloads": -1, "filename": "aiodine-1.2.4-py3-none-any.whl", "has_sig": false, "md5_digest": "2d113f10d055a96ef3dd33c95cfc1fbc", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23031, "upload_time": "2019-03-29T23:39:23", "url": "https://files.pythonhosted.org/packages/b5/e6/c468f9c2d0d9079bb2076c1488b7d1117e0ddcde46574a2820719094f9b5/aiodine-1.2.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "111292b59b90e25503b7c240a4589393", "sha256": "6e13c7d5003389c3f16afb69e88e54c04d6482f69a1ab36296afe89789936ef3" }, "downloads": -1, "filename": "aiodine-1.2.4.tar.gz", "has_sig": false, "md5_digest": "111292b59b90e25503b7c240a4589393", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20441, "upload_time": "2019-03-29T23:39:47", "url": "https://files.pythonhosted.org/packages/3a/1c/c656b56defeb6624d19cfba99cb38ec959a2329e94e409dd4d584f68176e/aiodine-1.2.4.tar.gz" } ], "1.2.5": [ { "comment_text": "", "digests": { "md5": "751f636327048e85cac42f8b40a8b43b", "sha256": "5c18dca9e5398e8dd0f9cbc728c00207de71e2d132c33005e38454f33fb5a82f" }, "downloads": -1, "filename": "aiodine-1.2.5-py3-none-any.whl", "has_sig": false, "md5_digest": "751f636327048e85cac42f8b40a8b43b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23108, "upload_time": "2019-03-30T10:22:20", "url": "https://files.pythonhosted.org/packages/9d/89/c440d32517d131bbe00295e220b0bf845f07625073e4fb3f691ad5499bad/aiodine-1.2.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9719e77721a16a5caa24ebff9f267785", "sha256": "7f58bdec4a33918c1f610f4491694cc6b547075f51c3a303077b722f777ca79d" }, "downloads": -1, "filename": "aiodine-1.2.5.tar.gz", "has_sig": false, "md5_digest": "9719e77721a16a5caa24ebff9f267785", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20500, "upload_time": "2019-03-30T10:22:22", "url": "https://files.pythonhosted.org/packages/9f/3e/9f9a1fc9dec825ecf8449c1acb4de098aaa9a7bc3a0ece805925332a3a2b/aiodine-1.2.5.tar.gz" } ], "1.2.6": [ { "comment_text": "", "digests": { "md5": "1769d2c3ea7bfaed8b0e666e7e25483a", "sha256": "eb692b622a0c6728b6325f488f758ff18e7274a651898934d7b2925980a23d58" }, "downloads": -1, "filename": "aiodine-1.2.6-py3-none-any.whl", "has_sig": false, "md5_digest": "1769d2c3ea7bfaed8b0e666e7e25483a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23104, "upload_time": "2019-05-08T12:19:49", "url": "https://files.pythonhosted.org/packages/37/6c/c9342ab36ea5c5ba151db3715fa7135c203d2e0fbb8bcd2b4e74e680f36f/aiodine-1.2.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7d74729da6fa2b2055c561bd5215dca1", "sha256": "dbc832aa68ca8e48d4156560358c7d98139399e52a8c5af6d45b8aa768722592" }, "downloads": -1, "filename": "aiodine-1.2.6.tar.gz", "has_sig": false, "md5_digest": "7d74729da6fa2b2055c561bd5215dca1", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 20492, "upload_time": "2019-05-08T12:19:51", "url": "https://files.pythonhosted.org/packages/e5/d6/75bba785806161c517d667c88d66ee9789c1a737b6e1187e6342d12d5bbf/aiodine-1.2.6.tar.gz" } ], "1.2.7": [ { "comment_text": "", "digests": { "md5": "f6a7f0734615d90068880cb8b060f834", "sha256": "fe407da4146bc907b9ace2817f17fb52406cebca8806894fef8523306117a083" }, "downloads": -1, "filename": "aiodine-1.2.7-py3-none-any.whl", "has_sig": false, "md5_digest": "f6a7f0734615d90068880cb8b060f834", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23391, "upload_time": "2019-06-19T20:37:58", "url": "https://files.pythonhosted.org/packages/42/d6/e3f2ec78538aeb4b2b0835eabd116910469099735c4eb1ff751f022d46a1/aiodine-1.2.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "398875334548830e87b08bb1f99c419d", "sha256": "bbea3dd6c1bfa3c2ece07fe38102b636cdcbc58d678e2e848205cc6d0c4f9639" }, "downloads": -1, "filename": "aiodine-1.2.7.tar.gz", "has_sig": false, "md5_digest": "398875334548830e87b08bb1f99c419d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17802, "upload_time": "2019-06-19T20:38:00", "url": "https://files.pythonhosted.org/packages/31/16/2c07be38a6fb8a7899291bfd01161d4a4111914e8280f2dfa24c9f82a28e/aiodine-1.2.7.tar.gz" } ], "1.2.8": [ { "comment_text": "", "digests": { "md5": "2be944954395497bdc30752504f7327a", "sha256": "3d8db019989e13de1622a24bd598fa0daa7584472bda041ba921ebc363166c5a" }, "downloads": -1, "filename": "aiodine-1.2.8-py3-none-any.whl", "has_sig": false, "md5_digest": "2be944954395497bdc30752504f7327a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23480, "upload_time": "2019-09-11T22:08:17", "url": "https://files.pythonhosted.org/packages/57/ef/910ef7ee8b55dbf8815fd993bbe42bb4a539d3a30535426cf96e94aa23c7/aiodine-1.2.8-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "95f5ca4bff95771267c317dd76b0083e", "sha256": "e1b6acf9c81e7903b7d2ce57b9b7fdc0eac74cb64ba251a8ea0cf780f22a21f1" }, "downloads": -1, "filename": "aiodine-1.2.8.tar.gz", "has_sig": false, "md5_digest": "95f5ca4bff95771267c317dd76b0083e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 18011, "upload_time": "2019-09-11T22:08:19", "url": "https://files.pythonhosted.org/packages/21/68/9e769e0be17acdcd1c8ab05768ac8fd654cf96aa11f1640cfc229e2bec22/aiodine-1.2.8.tar.gz" } ], "1.2.9": [ { "comment_text": "", "digests": { "md5": "861367834fd6c42a0ef621b894237b8a", "sha256": "a33a3809d9bf273ad576aff3231e29f532be4b63de9784e59f5b442a35f53709" }, "downloads": -1, "filename": "aiodine-1.2.9-py3-none-any.whl", "has_sig": false, "md5_digest": "861367834fd6c42a0ef621b894237b8a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23481, "upload_time": "2019-10-15T07:57:14", "url": "https://files.pythonhosted.org/packages/e8/81/a7f66cf01895b6b3867684e41c2593debd43257feb7e670fc115caca72fa/aiodine-1.2.9-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "eff1c3ab511995c794ce47aa8eeb028b", "sha256": "f4151ea1c4c3261041700720b1c5988425c5178d352f3934423ea5869debd1ea" }, "downloads": -1, "filename": "aiodine-1.2.9.tar.gz", "has_sig": false, "md5_digest": "eff1c3ab511995c794ce47aa8eeb028b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17975, "upload_time": "2019-10-15T07:57:17", "url": "https://files.pythonhosted.org/packages/a1/eb/c30e29f49de818124f0342681598c4d8ed3c1285a76e0db174120b74d8f4/aiodine-1.2.9.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "861367834fd6c42a0ef621b894237b8a", "sha256": "a33a3809d9bf273ad576aff3231e29f532be4b63de9784e59f5b442a35f53709" }, "downloads": -1, "filename": "aiodine-1.2.9-py3-none-any.whl", "has_sig": false, "md5_digest": "861367834fd6c42a0ef621b894237b8a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23481, "upload_time": "2019-10-15T07:57:14", "url": "https://files.pythonhosted.org/packages/e8/81/a7f66cf01895b6b3867684e41c2593debd43257feb7e670fc115caca72fa/aiodine-1.2.9-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "eff1c3ab511995c794ce47aa8eeb028b", "sha256": "f4151ea1c4c3261041700720b1c5988425c5178d352f3934423ea5869debd1ea" }, "downloads": -1, "filename": "aiodine-1.2.9.tar.gz", "has_sig": false, "md5_digest": "eff1c3ab511995c794ce47aa8eeb028b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 17975, "upload_time": "2019-10-15T07:57:17", "url": "https://files.pythonhosted.org/packages/a1/eb/c30e29f49de818124f0342681598c4d8ed3c1285a76e0db174120b74d8f4/aiodine-1.2.9.tar.gz" } ] }