{ "info": { "author": "Christian Glacet", "author_email": "cglacet@kune.tech", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "[![Travis status](https://travis-ci.com/cglacet/aiohttp-sessions-helpers.svg?branch=master)](https://travis-ci.com/cglacet/aiohttp-sessions-helpers)\n\n# Automatically add session management to a class\nSome function and classes to help you deal with aiohttp client sessions. This is made after this [discussion](https://github.com/aio-libs/aiohttp/pull/1468). This works for decorating both coroutines and asynchronous generators methods. \n\n## Installation\n\n```bash\npip install aiohttp-asynctools\n```\n\n## TL;DR\n\nAdd an `aiohttp.ClientSession` object to your class in a fast and clean way with the following 4 steps:\n\n1. Import asynctools\n2. Extend asynctools.AbstractSessionContainer\n3. (optional) Cutomize the session instanciation in your `__init__` method.\n4. Decorate asynchronous methods/generators with `@asynctools.attach_session` to attach a `session` argument. \n\nHere is what it looks like for a simple example using a math API ([http://api.mathjs.org/v4](http://api.mathjs.org/v4)): \n\n```python\nimport asyncio\nimport asynctools # 1.\n\nclass MathRequests(asynctools.AbstractSessionContainer): # 2.\n def __init__(self):\n super().__init__(raise_for_status=True) # 3. (optional)\n\n @asynctools.attach_session # 4.\n async def get_text(self, url, params, session=None):\n async with session.get(url, params=params) as response:\n return await response.text()\n async def get_square(self, value):\n return await self.get_text(\"http://api.mathjs.org/v4\", params={'expr' : '{}^2'.format(value)})\n```\nNote that the `__init__` method has to be here, if it is empty, just use the `pass` keyword as its content.\n\nYou are now ready to instantiate a `MathRequests` context manager and start requesting the math service using a single `aiohttp` `session` (the session is hidden from the `MathRequests` user):\n```python\nfrom aiohttp import web\nroutes = web.RouteTableDef()\n\n@routes.get('/squares')\nasync def index(request):\n tasks = []\n data = request.query\n values = data['values'].split(',')\n # Use the object as a context manager (async with as )\n async with MathRequests() as maths:\n results = await asyncio.gather(*[ maths.get_square(v) for v in values ])\n return web.json_response({ 'values':values, 'results':results })\n\nmaths_app = web.Application()\nmaths_app.add_routes(routes)\n```\n\n_Alternatively you can start/close sessions explicitly:_\n```python\n# ...\n maths.start_session()\n results = await asyncio.gather(*[ maths.get_square(v) for v in values ])\n maths.close_session()\n# ...\n```\n\nYou can now start your server and test the service (example here with gunicorn):\n```bash\ngunicorn math_requests:maths_app --bind localhost:8085 --worker-class aiohttp.GunicornWebWorker --reload\n```\n```bash\ncurl 'http://localhost:8085/squares?values=1,2,3,4,5,6,7,8,9,10'\n```\nWhich should output:\n```json\n{\n \"values\": [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\"],\n \"results\": [\"1\", \"4\", \"9\", \"16\", \"25\", \"36\", \"49\", \"64\", \"81\", \"100\"]\n}\n```\n\n## Details and explanation\n\n### What?\n\nThe goal is to help aiohttp users to build classes that will contain sessions object in an efficient/clean way.\n\n### Why?\n\nIf you want to build class that will make requests using **aiohttp client**, at some point you'll have to deal with sessions.\nThe [quickstart guide for aiohttp client](https://aiohttp.readthedocs.io/en/stable/client_quickstart.html#make-a-request) has an important note about sessions.\n\n>```python\n>import aiohttp\n>\n>async with aiohttp.ClientSession() as session:\n> async with session.get('http://httpbin.org/get') as resp:\n> print(resp.status)\n> print(await resp.text())\n>```\n>\n> ...\n>\n> ### Note\n> Don\u2019t create a session per request. Most likely you need a session per application which performs all requests altogether.\n>\n> More complex cases may require a session per site, e.g. one for Github and other one for Facebook APIs. Anyway making a session for every request is a **very bad** idea.\n>\n>A session contains a connection pool inside. Connection reusage and keep-alives (both are on by default) may speed up total performance.\n\nThe goal is to have a single session attached to a given object, this is where this module will give you a simple way of achieving this with only 4 (very simple) lines of code.\n\n### How?\n\nThe module provides an abstract class `AbstractSessionContainer` and a method decorator `attach_session` that you'll have to use to automatically add session management to an existing class.\n\nSay you have a class `MathRequests` that has a single method `get_square` that returns the square value of the given parameter using an `aiohttp.get` request to the math API service located at http://api.mathjs.org/v4. Here is what your class look like for now:\n\n```python\nimport asyncio, aiohttp\nroutes = aiohttp.web.RouteTableDef()\n\nclass MathRequests:\n async def get_text(self, url, params):\n # Remember \"making a session for every request is a very bad idea\"\n async with aiohttp.ClientSession() as session:\n async with session.get(url, params=params) as response:\n return await response.text()\n async def get_square(self, value):\n return await self.get_text(\"http://api.mathjs.org/v4\", params={'expr' : '{}^2'.format(value)})\n\n@routes.get('/squares')\nasync def index(request):\n tasks = []\n data = request.query\n values = data['values'].split(',')\n maths = MathRequests()\n results = await asyncio.gather(*[ maths.get_square(v) for v in values ])\n return web.json_response({ 'values':values, 'results':results })\n\nmaths_app = aiohttp.web.Application()\nmaths_app.add_routes(routes)\n```\nAs `aiohttp` documentation says, this is a bad idea to implement `MathRequests` this way, we need to share a single session for all `get_square` requests.\n\nA simple solution to this would be to store a client session object within `MathRequests`, which you could initiate in the `__init__` method. Saddly this is not a very clean solution as aiohttp sessions should be instantiated in a synchronous way (outside the even loop). See [aiohttp#1468](https://github.com/aio-libs/aiohttp/pull/1468) for more information about _creation a session outside of coroutine_.\n\nHere is the final solution using the provided module `asynctools`:\n```python\nimport asyncio\nimport asynctools # 1) Import\n\n# 2) Extends the abstract class that will handle the aiohttp session for you:\nclass MathRequests(asynctools.AbstractSessionContainer):\n def __init__(self):\n # 2') (optional) initilise with any 'aiohttp.ClientSession' argument\n super().__init__(raise_for_status=True)\n # 3) This decorator will automatically fill the session argument:\n @asynctools.attach_session\n async def get_text(self, url, params, session=None): # 4) Add the 'session' argument\n async with session.get(url, params=params) as response:\n return await response.text()\n async def get_square(self, value):\n return await self.get_text(\"http://api.mathjs.org/v4\", params={'expr' : '{}^2'.format(value)})\n\nfrom aiohttp import web\nroutes = web.RouteTableDef()\n\n@routes.get('/squares')\nasync def index(request):\n tasks = []\n data = request.query\n values = data['values'].split(',')\n async with MathRequests() as maths: # Use the object as a context manager (async with as )\n results = await asyncio.gather(*[ maths.get_square(v) for v in values ])\n return web.json_response({ 'values':values, 'results':results })\n\nmaths_app = web.Application()\nmaths_app.add_routes(routes)\n```\n\nUsing the `MathRequests` as a [context manager](https://docs.python.org/3/library/stdtypes.html#typecontextmanager) is the best option (as it will make sure the session is correctly started and closed), but it's not the only option, you can also keep your code as it was before:\n```python\n@routes.get('/squares')\nasync def index(request):\n tasks = []\n data = request.query\n values = data['values'].split(',')\n maths = MathRequests()\n results = await asyncio.gather(*[ maths.get_square(v) for v in values ])\n return web.json_response({ 'values':values, 'results':results })\n```\nIn this case, no session is attached to the `maths` object and every call to `get_square` will use a different session (which is as bad as it was with the old version of `MathRequests`). What you can do to avoid that is to **explicitly open a \"math session\"** which will make all `get_square` calls to use the same session (also, don't forget to close the session when you are done):\n```python\n@routes.get('/maths')\nasync def index(request):\n tasks = []\n data = request.query\n values = data['values'].split(',')\n maths = MathRequests()\n maths.start_session()\n results = await asyncio.gather(*[ maths.get_square(v) for v in values ])\n maths.close_session()\n return web.json_response({ 'values':values, 'results':results })\n```\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/cglacet/aiohttp-sessions-helpers", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "aiohttp-asynctools", "package_url": "https://pypi.org/project/aiohttp-asynctools/", "platform": "", "project_url": "https://pypi.org/project/aiohttp-asynctools/", "project_urls": { "Bug Reports": "https://github.com/cglacet/aiohttp-sessions-helpers/issues", "Homepage": "https://github.com/cglacet/aiohttp-sessions-helpers", "Source": "https://github.com/cglacet/aiohttp-sessions-helpers/" }, "release_url": "https://pypi.org/project/aiohttp-asynctools/0.1.2/", "requires_dist": [ "aiohttp (>=3.3)" ], "requires_python": "", "summary": "Some function and classes to help you deal with aiohttp sessions", "version": "0.1.2" }, "last_serial": 5352903, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "f05161a25ecf89f855ea67a1c9b4affc", "sha256": "c99fb47dba363ed280f2b6ffec5538b28c4a392f6698c9e62831bbca43df7908" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "f05161a25ecf89f855ea67a1c9b4affc", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8140, "upload_time": "2018-06-25T14:30:18", "url": "https://files.pythonhosted.org/packages/19/05/17e40bf292879f027e4fad417935bdf1d9e3a0829845e61f24de68a4650a/aiohttp_asynctools-0.0.1-py3-none-any.whl" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "3bf8360483ded1c3f4651bab7703fc61", "sha256": "f78c8d9b9621373b90d61b9df89be2a3dab7ad587aa5d6a206d1a59473730456" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "3bf8360483ded1c3f4651bab7703fc61", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4647, "upload_time": "2018-06-25T14:41:28", "url": "https://files.pythonhosted.org/packages/52/f1/38b680ee953943e56221fbf07a628dabc38bbba65bdf316f7c62ea4de780/aiohttp_asynctools-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7adbb12b0a6b6d543df093d43a12f7d9", "sha256": "74d5c77fd5d8e565dd2c2581154bbd4536d2a12fda91fd660dcce561cd0fd018" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.2.tar.gz", "has_sig": false, "md5_digest": "7adbb12b0a6b6d543df093d43a12f7d9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4684, "upload_time": "2018-06-25T14:41:30", "url": "https://files.pythonhosted.org/packages/f2/e3/44eda8c93b383941a85fb7828e8eb299ce90d7ded33884e0e47b11c597af/aiohttp_asynctools-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "ab3aaac67b8844c79cb2888a57e63264", "sha256": "76709b479a4b089ecf0e5788155d0f4a38220f69c0b9ffce5d9a04d13e003e60" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "ab3aaac67b8844c79cb2888a57e63264", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4676, "upload_time": "2018-06-25T15:45:47", "url": "https://files.pythonhosted.org/packages/d7/c5/559000dcefbef4c35757ef1e56f82f087a2a1c29639a357971450d8090ce/aiohttp_asynctools-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c76eba585d321f0930c7fa38bb9f4c65", "sha256": "e52f617ad50d3b5b51b1f1347a4aa45533a0096296f3e4e8faeb3937bff3d6bd" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.3.tar.gz", "has_sig": false, "md5_digest": "c76eba585d321f0930c7fa38bb9f4c65", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4714, "upload_time": "2018-06-25T15:45:49", "url": "https://files.pythonhosted.org/packages/d4/f1/a31b5ed6360009944005a2e7851c68b01195f196b301aaed9d7e03a92df9/aiohttp_asynctools-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "84d72d012420c0ee01c9bae3d9c649f7", "sha256": "05e9332acda78b8a2ba302323c349273364ce91b7bd413af8558d8859d826ca9" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "84d72d012420c0ee01c9bae3d9c649f7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4668, "upload_time": "2018-06-25T16:11:27", "url": "https://files.pythonhosted.org/packages/65/13/cde2ead3b800602f22689deca631cae71c4140319d4029548032ef468c70/aiohttp_asynctools-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b6d129e96a677555a283e0e4e9b7c5d5", "sha256": "1ed160b506f398c1d25afddb3ee3374e20df6dc889e371b8682b0b7961091fe5" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.4.tar.gz", "has_sig": false, "md5_digest": "b6d129e96a677555a283e0e4e9b7c5d5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4704, "upload_time": "2018-06-25T16:11:29", "url": "https://files.pythonhosted.org/packages/6f/50/f4dc20c00cee7dbaa715e5580fd444e95f0ebfce1fc9575e8a2cf67e7336/aiohttp_asynctools-0.0.4.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "347117862ea4a61d3eb7ea720c143070", "sha256": "8c3cc5f9856411e8c141dcc7193fd2a587c1e6f4fff05198d202466fb9153cc6" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "347117862ea4a61d3eb7ea720c143070", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4727, "upload_time": "2018-06-25T23:44:54", "url": "https://files.pythonhosted.org/packages/fb/1e/4a5d8bb3f129ee58486aee876690e354b700e33bba4c4a518f51a5e19aab/aiohttp_asynctools-0.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e35a6c5008ef548451f573695c52ce92", "sha256": "0040a23694b57a4aabce7f57a2345a451fd2367b493b5b306f130ef8c13ed235" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.5.tar.gz", "has_sig": false, "md5_digest": "e35a6c5008ef548451f573695c52ce92", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4761, "upload_time": "2018-06-25T23:44:55", "url": "https://files.pythonhosted.org/packages/b1/b9/4d397d23bc9d23b4e26cf4253f0e025e8c3f53dd64b529be1a463e7badc6/aiohttp_asynctools-0.0.5.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "82f1d7c732ed145dd4d80d7ccbef0d76", "sha256": "30976ac3c5d4bc513a6c1d99cfdcd2cf77c2da0b7a8c8524efd4a5610f4f4d6d" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.6-py3-none-any.whl", "has_sig": false, "md5_digest": "82f1d7c732ed145dd4d80d7ccbef0d76", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4724, "upload_time": "2018-06-26T00:01:45", "url": "https://files.pythonhosted.org/packages/37/02/d036325cae245db784e336f685c6731e97232f539b111663a9bc71c880d3/aiohttp_asynctools-0.0.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "46dc113561c4ae5f2cc696d61e179a8c", "sha256": "37e21c97e81079779b3bc5ce71ee52c5adb69d09b172eacb8b5506b0c502a758" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.6.tar.gz", "has_sig": false, "md5_digest": "46dc113561c4ae5f2cc696d61e179a8c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4761, "upload_time": "2018-06-26T00:01:46", "url": "https://files.pythonhosted.org/packages/92/7c/1db233fc7ea356460f4d6aa72fc410d6306a3bad9553ff4b2ad48cf2e472/aiohttp_asynctools-0.0.6.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "fd6e63bc33500dcb24cb07c97ca5aece", "sha256": "b1375404022012767f08fe5a0b35c5f53c0b04728644b0453e954f22710327aa" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "fd6e63bc33500dcb24cb07c97ca5aece", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4785, "upload_time": "2018-06-26T09:04:00", "url": "https://files.pythonhosted.org/packages/eb/ba/176f6acf82902d76deac14e7030ca81326d38d061600a4e90b7b603b2ea6/aiohttp_asynctools-0.0.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "23d105074114ac6888a4f0cf58f7583b", "sha256": "0759c82de379e16bb93b3e394b7394a28fd610f06d81bc131ec04a7bdb270ebf" }, "downloads": -1, "filename": "aiohttp_asynctools-0.0.7.tar.gz", "has_sig": false, "md5_digest": "23d105074114ac6888a4f0cf58f7583b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4819, "upload_time": "2018-06-26T09:04:01", "url": "https://files.pythonhosted.org/packages/d0/99/03edebf9d4acb1862abdc819133b708415b9c769b323cdd2700dc3b2ef95/aiohttp_asynctools-0.0.7.tar.gz" } ], "0.1": [ { "comment_text": "", "digests": { "md5": "7b0857e0694cb00de4ae3005bc98a477", "sha256": "23a380c7346a0e65a659f1a0262f08648e237adf5b97647d72780f5559228e56" }, "downloads": -1, "filename": "aiohttp_asynctools-0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7b0857e0694cb00de4ae3005bc98a477", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7477, "upload_time": "2019-04-24T15:22:06", "url": "https://files.pythonhosted.org/packages/69/c4/e54cc84b8127a55a3ed3bac32d6358e47cf5a300e90b62331ddc11d2cc40/aiohttp_asynctools-0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7ac269a664952ca16f8067e7b55f3c93", "sha256": "89ba3dd994e6ecc66de5d205d2970c70c2a9e3e874766b43e0fbefcfe4b3b34d" }, "downloads": -1, "filename": "aiohttp_asynctools-0.1.tar.gz", "has_sig": false, "md5_digest": "7ac269a664952ca16f8067e7b55f3c93", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4896, "upload_time": "2019-04-24T15:21:29", "url": "https://files.pythonhosted.org/packages/5d/b2/81593ec71b366b8f04913b73f576d57d972400755b02c9ff50937f73a03c/aiohttp_asynctools-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "6edb56cb7dc118956c2d4f7a635bd6ac", "sha256": "fa57d22bf46d5a4244257a979d7cbe2ba65dd2404cd1293f1e702718f18f9a0f" }, "downloads": -1, "filename": "aiohttp_asynctools-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "6edb56cb7dc118956c2d4f7a635bd6ac", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7502, "upload_time": "2019-04-24T22:55:45", "url": "https://files.pythonhosted.org/packages/79/96/8d1cac93b755f939c42eab749dc2ba3955b04e27a70764f523c4f258c766/aiohttp_asynctools-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a727f213a33d3e8b3774b5043df21e4d", "sha256": "cc499bc4f52cc5bec404883ec4519b75166daf2c699107f67f19e8edee567cf9" }, "downloads": -1, "filename": "aiohttp_asynctools-0.1.1.tar.gz", "has_sig": false, "md5_digest": "a727f213a33d3e8b3774b5043df21e4d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4889, "upload_time": "2019-04-24T22:54:22", "url": "https://files.pythonhosted.org/packages/62/62/c7fc695df4d617c0d117440afb5f00184e87aebff7bca8e65acc2206db13/aiohttp_asynctools-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "dce6ff66f20cfbc8b76c85d674a153a9", "sha256": "c39581ffb9b44733a621e500291afaf924497796954ac027c90df11d370e3baf" }, "downloads": -1, "filename": "aiohttp_asynctools-0.1.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "dce6ff66f20cfbc8b76c85d674a153a9", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 8130, "upload_time": "2019-06-03T14:40:35", "url": "https://files.pythonhosted.org/packages/76/ba/341119aee50ed8c16331861a966b8bc398c1fa82e555141f77760ee3d93a/aiohttp_asynctools-0.1.2-py2.py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "dce6ff66f20cfbc8b76c85d674a153a9", "sha256": "c39581ffb9b44733a621e500291afaf924497796954ac027c90df11d370e3baf" }, "downloads": -1, "filename": "aiohttp_asynctools-0.1.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "dce6ff66f20cfbc8b76c85d674a153a9", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 8130, "upload_time": "2019-06-03T14:40:35", "url": "https://files.pythonhosted.org/packages/76/ba/341119aee50ed8c16331861a966b8bc398c1fa82e555141f77760ee3d93a/aiohttp_asynctools-0.1.2-py2.py3-none-any.whl" } ] }