asyncio-thread-runner


Nameasyncio-thread-runner JSON
Version 1.0 PyPI version JSON
download
home_pageNone
SummaryRun async code from sync code.
upload_time2025-08-19 17:37:24
maintainerNone
docs_urlNone
authorlemon24
requires_python>=3.11
licenseNone
keywords async sync asyncio runner thread
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            *you can have a little async (as a treat)*


[![build status](https://github.com/lemon24/asyncio-thread-runner/actions/workflows/tests.yaml/badge.svg)](https://github.com/lemon24/asyncio-thread-runner/actions/workflows/tests.yaml)
[![PyPI status](https://img.shields.io/pypi/v/asyncio-thread-runner.svg)](https://pypi.python.org/pypi/asyncio-thread-runner)


**asyncio-thread-runner** allows you to run async code from sync code.

This is useful when you're doing some sync stuff, but:

* you also need to do some async stuff, **without** making **everything async**
* maybe the sync stuff is an existing application
* maybe you still want to use your favorite sync library
* or maybe you need just a little async, without having to pay the full price

Features:

* unlike [asyncio.run()], it provides a **long-lived event loop**
* unlike [asyncio.Runner], it runs in a dedicated thread, and you can use it from **multiple threads**
* it allows you to use **async context managers** and **iterables** from sync code
* check out [this article](https://death.andgravity.com/asyncio-bridge) for why these are useful


Usage:

```shell
$ pip install asyncio-thread-runner
```

```python
>>> async def double(i):
...     return i * 2
...
>>> from asyncio_thread_runner import ThreadRunner
>>> runner = ThreadRunner()
>>> runner.run(double(2))
4
```


Annotated example:

```python
import aiohttp
from asyncio_thread_runner import ThreadRunner

# you can use ThreadRunner as a context manager,
# or call runner.close() when you're done with it
with ThreadRunner() as runner:

    # aiohttp.ClientSession() should be used as an async context manager,
    # enter_context() will exit the context on runner shutdown;
    # because instantiating ClientSession requires a running event loop,
    # we pass it as a factory instead of calling it in the main thread
    session = runner.enter_context(aiohttp.ClientSession)

    # session.get() returns an async context manager...
    request = session.get('https://death.andgravity.com/asyncio-bridge')
    # which we turn into a normal one with wrap_context()
    with runner.wrap_context(request) as response:

        # response.content is an async iterator;
        # we turn it into a normal iterator with wrap_iter()
        lines = list(runner.wrap_iter(response.content))

    # "got 935 lines"
    print('got', len(lines), 'lines')

```


[asyncio.run()]: https://docs.python.org/3/library/asyncio-runner.html#asyncio.run
[asyncio.Runner]: https://docs.python.org/3/library/asyncio-runner.html#asyncio.Runner


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "asyncio-thread-runner",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "async, sync, asyncio, runner, thread",
    "author": "lemon24",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/03/fd/1b5b3452f9e7df89b0c9bd246d276e0ae3a6b6bd7304076e09f2df1bf9fb/asyncio_thread_runner-1.0.tar.gz",
    "platform": null,
    "description": "*you can have a little async (as a treat)*\n\n\n[![build status](https://github.com/lemon24/asyncio-thread-runner/actions/workflows/tests.yaml/badge.svg)](https://github.com/lemon24/asyncio-thread-runner/actions/workflows/tests.yaml)\n[![PyPI status](https://img.shields.io/pypi/v/asyncio-thread-runner.svg)](https://pypi.python.org/pypi/asyncio-thread-runner)\n\n\n**asyncio-thread-runner** allows you to run async code from sync code.\n\nThis is useful when you're doing some sync stuff, but:\n\n* you also need to do some async stuff, **without** making **everything async**\n* maybe the sync stuff is an existing application\n* maybe you still want to use your favorite sync library\n* or maybe you need just a little async, without having to pay the full price\n\nFeatures:\n\n* unlike [asyncio.run()], it provides a **long-lived event loop**\n* unlike [asyncio.Runner], it runs in a dedicated thread, and you can use it from **multiple threads**\n* it allows you to use **async context managers** and **iterables** from sync code\n* check out [this article](https://death.andgravity.com/asyncio-bridge) for why these are useful\n\n\nUsage:\n\n```shell\n$ pip install asyncio-thread-runner\n```\n\n```python\n>>> async def double(i):\n...     return i * 2\n...\n>>> from asyncio_thread_runner import ThreadRunner\n>>> runner = ThreadRunner()\n>>> runner.run(double(2))\n4\n```\n\n\nAnnotated example:\n\n```python\nimport aiohttp\nfrom asyncio_thread_runner import ThreadRunner\n\n# you can use ThreadRunner as a context manager,\n# or call runner.close() when you're done with it\nwith ThreadRunner() as runner:\n\n    # aiohttp.ClientSession() should be used as an async context manager,\n    # enter_context() will exit the context on runner shutdown;\n    # because instantiating ClientSession requires a running event loop,\n    # we pass it as a factory instead of calling it in the main thread\n    session = runner.enter_context(aiohttp.ClientSession)\n\n    # session.get() returns an async context manager...\n    request = session.get('https://death.andgravity.com/asyncio-bridge')\n    # which we turn into a normal one with wrap_context()\n    with runner.wrap_context(request) as response:\n\n        # response.content is an async iterator;\n        # we turn it into a normal iterator with wrap_iter()\n        lines = list(runner.wrap_iter(response.content))\n\n    # \"got 935 lines\"\n    print('got', len(lines), 'lines')\n\n```\n\n\n[asyncio.run()]: https://docs.python.org/3/library/asyncio-runner.html#asyncio.run\n[asyncio.Runner]: https://docs.python.org/3/library/asyncio-runner.html#asyncio.Runner\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Run async code from sync code.",
    "version": "1.0",
    "project_urls": {
        "Changelog": "https://github.com/lemon24/asyncio-thread-runner/blob/main/CHANGES.md",
        "Documentation": "https://github.com/lemon24/asyncio-thread-runner/blob/main/README.md",
        "Issues": "https://github.com/lemon24/asyncio-thread-runner/issues",
        "Repository": "https://github.com/lemon24/asyncio-thread-runner"
    },
    "split_keywords": [
        "async",
        " sync",
        " asyncio",
        " runner",
        " thread"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8d871fead469bb900643e2962aaf49b2b69f0e3222b652fd78d3a8df6fbb0e17",
                "md5": "8a2daaf32a187b4a72cde07ab44caf53",
                "sha256": "d7cc3f8b2f8446ac9450132ae8372a4810734ea8399e20d4233cc43920d8c812"
            },
            "downloads": -1,
            "filename": "asyncio_thread_runner-1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8a2daaf32a187b4a72cde07ab44caf53",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 5067,
            "upload_time": "2025-08-19T17:37:23",
            "upload_time_iso_8601": "2025-08-19T17:37:23.037783Z",
            "url": "https://files.pythonhosted.org/packages/8d/87/1fead469bb900643e2962aaf49b2b69f0e3222b652fd78d3a8df6fbb0e17/asyncio_thread_runner-1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "03fd1b5b3452f9e7df89b0c9bd246d276e0ae3a6b6bd7304076e09f2df1bf9fb",
                "md5": "72f86f28aee0b175c7d54613770cb0db",
                "sha256": "9b3f6c30d3ee8ae5cca1a243b6bb872404bdbcd88ec39fbbffa7984b96493182"
            },
            "downloads": -1,
            "filename": "asyncio_thread_runner-1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "72f86f28aee0b175c7d54613770cb0db",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 7630,
            "upload_time": "2025-08-19T17:37:24",
            "upload_time_iso_8601": "2025-08-19T17:37:24.303129Z",
            "url": "https://files.pythonhosted.org/packages/03/fd/1b5b3452f9e7df89b0c9bd246d276e0ae3a6b6bd7304076e09f2df1bf9fb/asyncio_thread_runner-1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-19 17:37:24",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "lemon24",
    "github_project": "asyncio-thread-runner",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "asyncio-thread-runner"
}
        
Elapsed time: 2.68948s