async_cast
==========
|.github/workflows/tests.yml|
Cast async function to blocking and viceversa. (works on python 3.7 and
up) Also run functions in threads, whether async or blocking.
Why ``async_cast``?
-------------------
I found the current ``asyncio`` tools frustrating when migrating from
blocking code. If you want to profit IO operations to *“run something
else”* you need to rewrite all code to use asyncio. When you start form
scratch that’s acceptable, but not with legacy code.
So with this small self-contained library you can easily convert legacy
code into async code. The best way is running several blocking function
in different threads. But **be aware** that threads also bring race
conditions, so make sure concurrent functions are thread-safe.
Installing
----------
https://pypi.org/project/async-cast/
::
pip install -U async-cast
The package is a single module that you can easily audit.
Decorator: casting ``async`` function to a blocking function
------------------------------------------------------------
.. code:: python
from async_cast import also_blocking
@also_blocking
async def request_url(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
if __name__ == '__main__':
print(request_url.blocking('https://github.com'))
Decorator: casting a blocking function to ``async`` function
------------------------------------------------------------
.. code:: python
from async_cast import also_async
import asyncio
@also_async
def request_url(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
async def main():
print(await request_url.async_('https://github.com'))
if __name__ == '__main__':
asyncio.run(main())
Running tasks in a ThreadPool
-----------------------------
I wrapped existing ``ThreadPoolExecutor`` to make it easier to run tasks
inside it. Tasks are automatically registered in the pool declared by
the ``with thread_pool(...):`` context.
Running ``async`` function in threadpool
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
from async_cast import also_blocking, thread_pool
import asyncio
@also_blocking
async def request_url(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
async def main():
with thread_pool(3):
t1 = request_url.async_thread('https://github.com')
t2 = request_url.async_thread('https://google.com')
t3 = request_url.async_thread('https://facebook.com')
results = await asyncio.gather(t1,t2,t3)
print(results)
if __name__ == '__main__':
asyncio.run(main())
Running blocking function in threadpool
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
from async_cast import also_async, thread_pool
import asyncio
@also_async
def request_url(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
async def main():
with thread_pool(3):
t1 = request_url.async_thread('https://github.com')
t2 = request_url.async_thread('https://google.com')
t3 = request_url.async_thread('https://facebook.com')
results = await asyncio.gather(t1,t2,t3)
print(results)
if __name__ == '__main__':
asyncio.run(main())
Non decorators alternatives
---------------------------
Casting ``async`` function to a blocking function with ``to_blocking``
----------------------------------------------------------------------
.. code:: python
from async_cast import to_blocking
async def request_url(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
if __name__ == '__main__':
print(to_blocking(request_url)('https://github.com'))
Casting a blocking function to ``async`` function with ``to_async``
-------------------------------------------------------------------
.. code:: python
from async_cast import to_async
import asyncio
def request_url(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
async def main():
print(await to_async(request_url)('https://github.com'))
if __name__ == '__main__':
asyncio.run(main())
Running ``async`` or blocking function in threadpool with ``to_async_thread``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
from async_cast import to_async_thread, thread_pool
import asyncio
async def request_url(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
def request_url_blocking(url, **kwargs):
print(f'Requesting {url} with options {kwargs}')
...
result = f'<h1>{url}</h1>'
return result
async def main():
with thread_pool(3):
t1 = to_async_thread(request_url)('https://github.com')
t2 = to_async_thread(request_url)('https://google.com')
t3 = to_async_thread(request_url)('https://facebook.com')
t4 = to_async_thread(request_url_blocking)('https://duckduckgo.com')
results = await asyncio.gather(t1,t2,t3,t4)
print(results)
if __name__ == '__main__':
asyncio.run(main())
.. |.github/workflows/tests.yml| image:: https://github.com/joaduo/async_cast/actions/workflows/tests.yml/badge.svg
:target: https://github.com/joaduo/async_cast/actions/workflows/tests.yml
Raw data
{
"_id": null,
"home_page": "https://github.com/joaduo/async_cast",
"name": "async-cast",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "asyncio,async,sync,casting,threads",
"author": "Joaquin Duo",
"author_email": "joaduo@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/f5/29/81488908353cc406212f8decde1ae624704b5d499fd09df7a36b1a476fbd/async_cast-0.6.1.tar.gz",
"platform": null,
"description": "async_cast\n==========\n\n|.github/workflows/tests.yml|\n\nCast async function to blocking and viceversa. (works on python 3.7 and\nup) Also run functions in threads, whether async or blocking.\n\nWhy ``async_cast``?\n-------------------\n\nI found the current ``asyncio`` tools frustrating when migrating from\nblocking code. If you want to profit IO operations to *\u201crun something\nelse\u201d* you need to rewrite all code to use asyncio. When you start form\nscratch that\u2019s acceptable, but not with legacy code.\n\nSo with this small self-contained library you can easily convert legacy\ncode into async code. The best way is running several blocking function\nin different threads. But **be aware** that threads also bring race\nconditions, so make sure concurrent functions are thread-safe.\n\nInstalling\n----------\n\nhttps://pypi.org/project/async-cast/\n\n::\n\n pip install -U async-cast\n\nThe package is a single module that you can easily audit.\n\nDecorator: casting ``async`` function to a blocking function\n------------------------------------------------------------\n\n.. code:: python\n\n from async_cast import also_blocking\n\n @also_blocking\n async def request_url(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n if __name__ == '__main__':\n print(request_url.blocking('https://github.com'))\n\nDecorator: casting a blocking function to ``async`` function\n------------------------------------------------------------\n\n.. code:: python\n\n from async_cast import also_async\n import asyncio\n\n @also_async\n def request_url(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n async def main():\n print(await request_url.async_('https://github.com'))\n\n if __name__ == '__main__':\n asyncio.run(main())\n\nRunning tasks in a ThreadPool\n-----------------------------\n\nI wrapped existing ``ThreadPoolExecutor`` to make it easier to run tasks\ninside it. Tasks are automatically registered in the pool declared by\nthe ``with thread_pool(...):`` context.\n\nRunning ``async`` function in threadpool\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n from async_cast import also_blocking, thread_pool\n import asyncio\n\n @also_blocking\n async def request_url(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n async def main():\n with thread_pool(3):\n t1 = request_url.async_thread('https://github.com')\n t2 = request_url.async_thread('https://google.com')\n t3 = request_url.async_thread('https://facebook.com')\n results = await asyncio.gather(t1,t2,t3)\n print(results)\n\n if __name__ == '__main__':\n asyncio.run(main())\n\nRunning blocking function in threadpool\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n from async_cast import also_async, thread_pool\n import asyncio\n\n @also_async\n def request_url(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n async def main():\n with thread_pool(3):\n t1 = request_url.async_thread('https://github.com')\n t2 = request_url.async_thread('https://google.com')\n t3 = request_url.async_thread('https://facebook.com')\n results = await asyncio.gather(t1,t2,t3)\n print(results)\n\n if __name__ == '__main__':\n asyncio.run(main())\n\nNon decorators alternatives\n---------------------------\n\nCasting ``async`` function to a blocking function with ``to_blocking``\n----------------------------------------------------------------------\n\n.. code:: python\n\n from async_cast import to_blocking\n\n async def request_url(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n if __name__ == '__main__':\n print(to_blocking(request_url)('https://github.com'))\n\nCasting a blocking function to ``async`` function with ``to_async``\n-------------------------------------------------------------------\n\n.. code:: python\n\n from async_cast import to_async\n import asyncio\n\n def request_url(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n async def main():\n print(await to_async(request_url)('https://github.com'))\n\n if __name__ == '__main__':\n asyncio.run(main())\n\nRunning ``async`` or blocking function in threadpool with ``to_async_thread``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n from async_cast import to_async_thread, thread_pool\n import asyncio\n\n async def request_url(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n def request_url_blocking(url, **kwargs):\n print(f'Requesting {url} with options {kwargs}')\n ...\n result = f'<h1>{url}</h1>'\n return result\n\n async def main():\n with thread_pool(3):\n t1 = to_async_thread(request_url)('https://github.com')\n t2 = to_async_thread(request_url)('https://google.com')\n t3 = to_async_thread(request_url)('https://facebook.com')\n t4 = to_async_thread(request_url_blocking)('https://duckduckgo.com')\n results = await asyncio.gather(t1,t2,t3,t4)\n print(results)\n\n if __name__ == '__main__':\n asyncio.run(main())\n\n.. |.github/workflows/tests.yml| image:: https://github.com/joaduo/async_cast/actions/workflows/tests.yml/badge.svg\n :target: https://github.com/joaduo/async_cast/actions/workflows/tests.yml\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Cast an async function to blocking function and viceversa. Also use threads pools if needed.",
"version": "0.6.1",
"project_urls": {
"Homepage": "https://github.com/joaduo/async_cast"
},
"split_keywords": [
"asyncio",
"async",
"sync",
"casting",
"threads"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f52981488908353cc406212f8decde1ae624704b5d499fd09df7a36b1a476fbd",
"md5": "fd5ec095e7276cd6cc922b8f04c05100",
"sha256": "42edcba10e06bd919a8462f12c4b30909c3d936cf00b38cea0ce111ef2440659"
},
"downloads": -1,
"filename": "async_cast-0.6.1.tar.gz",
"has_sig": false,
"md5_digest": "fd5ec095e7276cd6cc922b8f04c05100",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 4511,
"upload_time": "2023-12-19T09:41:59",
"upload_time_iso_8601": "2023-12-19T09:41:59.371469Z",
"url": "https://files.pythonhosted.org/packages/f5/29/81488908353cc406212f8decde1ae624704b5d499fd09df7a36b1a476fbd/async_cast-0.6.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-19 09:41:59",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "joaduo",
"github_project": "async_cast",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "async-cast"
}