# 🔀 Unparallel
<!-- --8<-- [start:index] -->
<div align="center" markdown="1">
Create async HTTP requests with Python in no time.
[![Build status](https://github.com/RafaelWO/unparallel/actions/workflows/test.yml/badge.svg?branch=main&event=push)](https://github.com/RafaelWO/unparallel/actions?query=workflow%3Atest)
![Coverage Report](https://raw.githubusercontent.com/RafaelWO/unparallel/main/assets/images/coverage.svg)
<br>
[![Package Version](https://img.shields.io/pypi/v/unparallel.svg)](https://pypi.org/project/unparallel/)
[![Python Version](https://img.shields.io/pypi/pyversions/unparallel.svg)](https://pypi.org/project/unparallel/)
<br>
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Security: bandit](https://img.shields.io/badge/security-bandit-green.svg)](https://github.com/PyCQA/bandit)
[![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/RafaelWO/unparallel/blob/main/.pre-commit-config.yaml)
[![License](https://img.shields.io/github/license/RafaelWO/unparallel)](https://github.com/RafaelWO/unparallel/blob/main/LICENSE)
<br>
[![Docs](https://img.shields.io/badge/docs-link-526cfe?style=for-the-badge)](https://rafaelwo.github.io/unparallel/)
[![Built with Material for MkDocs](https://img.shields.io/badge/Material_for_MkDocs-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white)](https://squidfunk.github.io/mkdocs-material/)
</div>
With Unparallel you can easily create thousands of web requests in an efficient way leveraging Python's async capabilities.
Unparallel is built on top of [HTTPX](https://github.com/encode/httpx/) and aims to support its rich set of features.
## Installation
```bash
pip install unparallel
```
## Example
A simple example of doing several GET requests to an HTTP web service:
```python
import asyncio
from unparallel import up
async def main():
urls = [f"https://httpbin.org/get?i={i}" for i in range(5)]
results = await up(urls)
print([item["args"] for item in results])
asyncio.run(main())
```
This prints:
```
Making async requests: 100%|███████████| 5/5 [00:00<00:00, 9.98it/s]
[{'i': '0'}, {'i': '1'}, {'i': '2'}, {'i': '3'}, {'i': '4'}]
```
Similarly, we can do a bunch of POST requests. This time we will use a single path but multiple payloads:
```python
import asyncio
from unparallel import up
async def main():
url = "https://httpbin.org/post"
payloads = [{"obj_id": i} for i in range(5)]
results = await up(url, method="post", payloads=payloads)
print([item["data"] for item in results])
asyncio.run(main())
```
This prints:
```
Making async requests: 100%|███████████| 5/5 [00:00<00:00, 9.98it/s]
['{"obj_id": 0}', '{"obj_id": 1}', '{"obj_id": 2}', '{"obj_id": 3}', '{"obj_id": 4}']
```
For more details on the usage and examples, check out the [docs][docs-usage].
## Why unparallel? Why async?
Async is a really powerful feature - especially when you have to wait for I/O.
Here is an example of making 20 web requests synchronously vs. asynchronously via `unparallel`.
![Sync-vs-Async][sync-async-gif]
As you can see, the async version finishes in less than a second.
<details><summary>Code for sync</summary>
```python
import httpx
from tqdm import tqdm
def main():
url = "https://httpbin.org"
paths = [f"/get?i={i}" for i in range(20)]
results = [
httpx.get(f"{url}{path}") for path in tqdm(paths, desc="Making sync requests")
]
assert len(results) == 20
if __name__ == "__main__":
main()
```
</details>
<details><summary>Code for async</summary>
```python
import asyncio
from unparallel import up
async def main():
url = "https://httpbin.org"
paths = [f"/get?i={i}" for i in range(20)]
results = await up(paths, base_url=url)
assert len(results) == 20
if __name__ == "__main__":
asyncio.run(main())
```
</details>
## Contributing
As this project is still in early development, I'm happy for any feedback and contributions!
Please refer to the [contributing guidelines][contrib] for details.
## License
This project is licensed under the terms of the `MIT` license. See [LICENSE](https://github.com/RafaelWO/unparallel/blob/main/LICENSE) for more details.
## Credits
This project was heavily inspired by the blog post [Making 1 million requests with python-aiohttp](https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html) by Paweł Miech.
I created this project with [python-package-template](https://github.com/TezRomacH/python-package-template).
<!-- --8<-- [end:index] -->
[docs-usage]: https://rafaelwo.github.io/unparallel/usage/
[sync-async-gif]: https://raw.githubusercontent.com/RafaelWO/unparallel/main/docs/assets/sync-vs-async.gif
[contrib]: https://github.com/RafaelWO/unparallel/blob/main/CONTRIBUTING.md
Raw data
{
"_id": null,
"home_page": "https://github.com/RafaelWO/unparallel",
"name": "unparallel",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "async,http,requests,network",
"author": "RafaelWO",
"author_email": "weingartner.rafael@hotmail.com",
"download_url": "https://files.pythonhosted.org/packages/d9/93/152375ea9c80cbaa3f4f33e75f071fbeb3076e9205e45170040172a4c708/unparallel-0.3.0.tar.gz",
"platform": null,
"description": "# \ud83d\udd00 Unparallel\n\n<!-- --8<-- [start:index] -->\n\n<div align=\"center\" markdown=\"1\">\n\nCreate async HTTP requests with Python in no time.\n\n[![Build status](https://github.com/RafaelWO/unparallel/actions/workflows/test.yml/badge.svg?branch=main&event=push)](https://github.com/RafaelWO/unparallel/actions?query=workflow%3Atest)\n![Coverage Report](https://raw.githubusercontent.com/RafaelWO/unparallel/main/assets/images/coverage.svg)\n<br>\n[![Package Version](https://img.shields.io/pypi/v/unparallel.svg)](https://pypi.org/project/unparallel/)\n[![Python Version](https://img.shields.io/pypi/pyversions/unparallel.svg)](https://pypi.org/project/unparallel/)\n<br>\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Security: bandit](https://img.shields.io/badge/security-bandit-green.svg)](https://github.com/PyCQA/bandit)\n[![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/RafaelWO/unparallel/blob/main/.pre-commit-config.yaml)\n[![License](https://img.shields.io/github/license/RafaelWO/unparallel)](https://github.com/RafaelWO/unparallel/blob/main/LICENSE)\n<br>\n[![Docs](https://img.shields.io/badge/docs-link-526cfe?style=for-the-badge)](https://rafaelwo.github.io/unparallel/)\n[![Built with Material for MkDocs](https://img.shields.io/badge/Material_for_MkDocs-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white)](https://squidfunk.github.io/mkdocs-material/)\n\n</div>\n\nWith Unparallel you can easily create thousands of web requests in an efficient way leveraging Python's async capabilities.\n\nUnparallel is built on top of [HTTPX](https://github.com/encode/httpx/) and aims to support its rich set of features.\n\n## Installation\n\n```bash\npip install unparallel\n```\n\n## Example\nA simple example of doing several GET requests to an HTTP web service:\n\n```python\nimport asyncio\nfrom unparallel import up\n\nasync def main():\n urls = [f\"https://httpbin.org/get?i={i}\" for i in range(5)]\n results = await up(urls)\n print([item[\"args\"] for item in results])\n\nasyncio.run(main())\n```\n\nThis prints:\n```\nMaking async requests: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 5/5 [00:00<00:00, 9.98it/s]\n[{'i': '0'}, {'i': '1'}, {'i': '2'}, {'i': '3'}, {'i': '4'}]\n```\n\n\nSimilarly, we can do a bunch of POST requests. This time we will use a single path but multiple payloads:\n\n```python\nimport asyncio\nfrom unparallel import up\n\nasync def main():\n url = \"https://httpbin.org/post\"\n payloads = [{\"obj_id\": i} for i in range(5)]\n results = await up(url, method=\"post\", payloads=payloads)\n print([item[\"data\"] for item in results])\n\nasyncio.run(main())\n```\n\nThis prints:\n```\nMaking async requests: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 5/5 [00:00<00:00, 9.98it/s]\n['{\"obj_id\": 0}', '{\"obj_id\": 1}', '{\"obj_id\": 2}', '{\"obj_id\": 3}', '{\"obj_id\": 4}']\n```\n\nFor more details on the usage and examples, check out the [docs][docs-usage].\n\n## Why unparallel? Why async?\nAsync is a really powerful feature - especially when you have to wait for I/O.\nHere is an example of making 20 web requests synchronously vs. asynchronously via `unparallel`.\n\n![Sync-vs-Async][sync-async-gif]\n\nAs you can see, the async version finishes in less than a second.\n\n<details><summary>Code for sync</summary>\n\n```python\nimport httpx\nfrom tqdm import tqdm\n\n\ndef main():\n url = \"https://httpbin.org\"\n paths = [f\"/get?i={i}\" for i in range(20)]\n results = [\n httpx.get(f\"{url}{path}\") for path in tqdm(paths, desc=\"Making sync requests\")\n ]\n assert len(results) == 20\n\n\nif __name__ == \"__main__\":\n main()\n```\n\n</details>\n\n<details><summary>Code for async</summary>\n\n```python\nimport asyncio\n\nfrom unparallel import up\n\n\nasync def main():\n url = \"https://httpbin.org\"\n paths = [f\"/get?i={i}\" for i in range(20)]\n\n results = await up(paths, base_url=url)\n\n assert len(results) == 20\n\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n</details>\n\n## Contributing\nAs this project is still in early development, I'm happy for any feedback and contributions! \nPlease refer to the [contributing guidelines][contrib] for details.\n\n## License\n\nThis project is licensed under the terms of the `MIT` license. See [LICENSE](https://github.com/RafaelWO/unparallel/blob/main/LICENSE) for more details.\n\n## Credits \nThis project was heavily inspired by the blog post [Making 1 million requests with python-aiohttp](https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html) by Pawe\u0142 Miech.\n\nI created this project with [python-package-template](https://github.com/TezRomacH/python-package-template).\n\n<!-- --8<-- [end:index] -->\n\n[docs-usage]: https://rafaelwo.github.io/unparallel/usage/\n[sync-async-gif]: https://raw.githubusercontent.com/RafaelWO/unparallel/main/docs/assets/sync-vs-async.gif\n[contrib]: https://github.com/RafaelWO/unparallel/blob/main/CONTRIBUTING.md\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Create async web requests in no time",
"version": "0.3.0",
"project_urls": {
"Homepage": "https://github.com/RafaelWO/unparallel",
"Repository": "https://github.com/RafaelWO/unparallel"
},
"split_keywords": [
"async",
"http",
"requests",
"network"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "aa237f93644df891489127e50a0e539f92dbb965001a2d63ec8174b1df40a6da",
"md5": "571dfc3c1eac627ec34ab930839b99d0",
"sha256": "18ced43c05e7267036670c3b3a00ccd5977f5284dcb3d9e1443950c1a0cdf5b3"
},
"downloads": -1,
"filename": "unparallel-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "571dfc3c1eac627ec34ab930839b99d0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8,<4.0",
"size": 8269,
"upload_time": "2024-03-02T16:44:13",
"upload_time_iso_8601": "2024-03-02T16:44:13.229406Z",
"url": "https://files.pythonhosted.org/packages/aa/23/7f93644df891489127e50a0e539f92dbb965001a2d63ec8174b1df40a6da/unparallel-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d993152375ea9c80cbaa3f4f33e75f071fbeb3076e9205e45170040172a4c708",
"md5": "63db8f582aac682f6e990b5e00e7b2f0",
"sha256": "72cb94c69ac97f4e4251b38892dc227b009a2a3c980e318dc73aaa52c8327409"
},
"downloads": -1,
"filename": "unparallel-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "63db8f582aac682f6e990b5e00e7b2f0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 8524,
"upload_time": "2024-03-02T16:44:14",
"upload_time_iso_8601": "2024-03-02T16:44:14.897132Z",
"url": "https://files.pythonhosted.org/packages/d9/93/152375ea9c80cbaa3f4f33e75f071fbeb3076e9205e45170040172a4c708/unparallel-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-03-02 16:44:14",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "RafaelWO",
"github_project": "unparallel",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "unparallel"
}