{"id":25536498,"url":"https://github.com/sonic182/aiosonic","last_synced_at":"2025-05-15T14:05:35.752Z","repository":{"id":37849507,"uuid":"197324152","full_name":"sonic182/aiosonic","owner":"sonic182","description":"A very fast Python asyncio http and websockets client","archived":false,"fork":false,"pushed_at":"2025-03-28T09:23:41.000Z","size":1426,"stargazers_count":163,"open_issues_count":11,"forks_count":19,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-14T16:59:40.614Z","etag":null,"topics":["asyncio","http","http-client","python","websockets"],"latest_commit_sha":null,"homepage":"https://aiosonic.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sonic182.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["sonic182"],"custom":["https://paypal.me/JohandersonMogollon"]}},"created_at":"2019-07-17T05:55:24.000Z","updated_at":"2025-04-16T20:46:12.000Z","dependencies_parsed_at":"2024-09-14T12:23:43.542Z","dependency_job_id":"1848ae25-376d-404e-a491-904a9b22f22c","html_url":"https://github.com/sonic182/aiosonic","commit_stats":null,"previous_names":[],"tags_count":60,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonic182%2Faiosonic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonic182%2Faiosonic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonic182%2Faiosonic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sonic182%2Faiosonic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sonic182","download_url":"https://codeload.github.com/sonic182/aiosonic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254355334,"owners_count":22057354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","http","http-client","python","websockets"],"created_at":"2025-02-20T04:36:17.669Z","updated_at":"2025-05-15T14:05:30.726Z","avatar_url":"https://github.com/sonic182.png","language":"Python","funding_links":["https://github.com/sponsors/sonic182","https://paypal.me/JohandersonMogollon"],"categories":[],"sub_categories":[],"readme":"![github status](https://github.com/sonic182/aiosonic/actions/workflows/python.yml/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/sonic182/aiosonic/badge.svg?branch=master)](https://coveralls.io/github/sonic182/aiosonic?branch=master)\n[![PyPI version](https://badge.fury.io/py/aiosonic.svg)](https://badge.fury.io/py/aiosonic)\n[![Documentation Status](https://readthedocs.org/projects/aiosonic/badge/?version=latest)](https://aiosonic.readthedocs.io/en/latest/?badge=latest)\n[![Discord](https://img.shields.io/discord/898929656969965648)](https://discord.gg/e7tBnYSRjj)\n\n# aiosonic - lightweight Python asyncio HTTP/WebSocket client\n\nA very fast, lightweight Python asyncio HTTP/1.1, HTTP/2, and WebSocket client.\n\n\nThe repository is hosted on [GitHub](https://github.com/sonic182/aiosonic).\n\nFor full documentation, please see [aiosonic docs](https://aiosonic.readthedocs.io/en/latest/).\n\n## Features\n\n- Keepalive support and smart pool of connections\n- Multipart file uploads\n- Handling of chunked responses and requests\n- Connection timeouts and automatic decompression\n- Automatic redirect following\n- Fully type-annotated\n- WebSocket support\n- (Nearly) 100% test coverage\n- HTTP/2 (BETA; enabled with a flag)\n\n## Requirements\n\n- Python \u003e= 3.8 (or PyPy 3.8+)\n\n## Installation\n\n```bash\npip install aiosonic\n```\n\n## Getting Started\n\nBelow is an example demonstrating basic HTTP client usage:\n\n```python\nimport asyncio\nimport aiosonic\nimport json\n\nasync def run():\n    client = aiosonic.HTTPClient()\n\n    # Sample GET request\n    response = await client.get('https://www.google.com/')\n    assert response.status_code == 200\n    assert 'Google' in (await response.text())\n\n    # POST data as multipart form\n    url = \"https://postman-echo.com/post\"\n    posted_data = {'foo': 'bar'}\n    response = await client.post(url, data=posted_data)\n    assert response.status_code == 200\n    data = json.loads(await response.content())\n    assert data['form'] == posted_data\n\n    # POST data as JSON\n    response = await client.post(url, json=posted_data)\n    assert response.status_code == 200\n    data = json.loads(await response.content())\n    assert data['json'] == posted_data\n\n    # GET request with timeouts\n    from aiosonic.timeout import Timeouts\n    timeouts = Timeouts(sock_read=10, sock_connect=3)\n    response = await client.get('https://www.google.com/', timeouts=timeouts)\n    assert response.status_code == 200\n    assert 'Google' in (await response.text())\n\n    print('HTTP client success')\n\nif __name__ == '__main__':\n    asyncio.run(run())\n```\n\n## WebSocket Usage\n\nBelow is an example demonstrating how to use aiosonic's WebSocket support:\n\n```python\nimport asyncio\nfrom aiosonic import WebSocketClient\n\nasync def main():\n    # Replace with your WebSocket server URL\n    ws_url = \"ws://localhost:8080\"\n    async with WebSocketClient() as client:\n        async with await client.connect(ws_url) as ws:\n            # Send a text message\n            await ws.send_text(\"Hello WebSocket\")\n            \n            # Receive an echo response\n            response = await ws.receive_text()\n            print(\"Received:\", response)\n            \n            # Send a ping and wait for the pong\n            await ws.ping(b\"keep-alive\")\n            pong = await ws.receive_pong()\n            print(\"Pong received:\", pong)\n\n            # You can have a \"reader\" task like this:\n            async def ws_reader(conn):\n                async for msg in conn:\n                    # handle the message...\n                    # msg is an instance of aiosonic.web_socket_client.Message dataclass.\n                    pass\n\n            asyncio.create_task(ws_reader(ws))\n            \n            # Gracefully close the connection (optional)\n            await ws.close(code=1000, reason=\"Normal closure\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n## Api Wrapping\n\nYou can easily wrap apis with `AioSonicBaseClient` class\n\n```python\nimport asyncio\nimport json\nfrom aiosonic.base_client import AioSonicBaseClient\n\nclass GitHubAPI(AioSonicBaseClient):\n    base_url = \"https://api.github.com\"\n    default_headers = {\n        \"Accept\": \"application/vnd.github+json\",\n        \"X-GitHub-Api-Version\": \"2022-11-28\",\n        # \"Authorization\": \"Bearer YOUR_GITHUB_TOKEN\",\n    }\n\n    async def users(self, username: str, **kwargs):\n        # base_url and headers are applied internally.\n        return await self.get(f\"/users/{username}\", **kwargs)\n    \n    async def update_repo(self, owner: str, repo: str, description: str):\n        data = {\n            \"name\": repo,\n            \"description\": description,\n        }\n        return await self.put(f\"/repos/{owner}/{repo}\", json=data)\n\n\nasync def main():\n    # You can pass an existing aiosonic.HTTPClient() instance in the constructor.\n    # If not provided, AioSonicBaseClient will create a new instance automatically.\n    github = GitHubAPI()\n    # Call the custom 'users' method to get data for user \"sonic182\"\n    user_data = await github.users(\"sonic182\")\n    print(json.dumps(user_data, indent=2))\n\n\nif __name__ == '__main__':\n    asyncio.run(main())\n```\n\nNote: You may wanna do a singleton of your clients implementations in order to reuse the internal HTTPClient instance, and it's pool of connections (efficient usage of the client), an example:\n\n```python\nclass SingletonMixin:\n    _instances = {}\n\n    def __new__(cls, *args, **kwargs):\n        if cls not in cls._instances:\n            cls._instances[cls] = super().__new__(cls)\n        return cls._instances[cls]\n\nclass GitHubAPI(AioSonicBaseClient, SingletonMixin):\n    base_url = \"https://api.github.com\"\n    # ... the rest of the code\n\n# now, each instance of the class will be the first created\ngh = GitHubAPI()\ng2 = GitHubAPI()\n\ngh == gh2\n```\n\n## Benchmarks\n\nA simple performance benchmark script is included in the `tests` folder. For example:\n\n```bash\npython tests/performance.py\n```\n\nExample output:\n\n```json\ndoing tests...\n{\n \"aiosonic\": \"1000 requests in 105.53 ms\",\n \"aiosonic cyclic\": \"1000 requests in 104.08 ms\",\n \"aiohttp\": \"1000 requests in 184.51 ms\",\n \"requests\": \"1000 requests in 1644.21 ms\"\n}\naiosonic is 74.84% faster than aiohttp\naiosonic is 1457.99% faster than requests\naiosonic is -1.38% faster than aiosonic cyclic\n```\n\n\u003e **Note:**  \n\u003e These benchmarks are basic and machine-dependent. They are intended as a rough comparison.\n\n## [TODO's](https://github.com/sonic182/aiosonic/projects/1)\n\n- **HTTP/2:**\n  - [x] GET requests\n  - [x] Requests with data sending\n  - [ ] Stable HTTP/2 release\n- Better documentation\n- International domains and URLs (IDNA + cache)\n- Basic/Digest authentication\n- [x] HTTP proxy support\n- [x] Sessions with cookie persistence\n- [x] Elegant key/value cookies\n\n## Development\n\nInstall development dependencies with Poetry:\n\n```bash\npoetry install\n```\n\nIt is recommended to install Poetry in a separate virtual environment (via apt, pacman, etc.) rather than in your development environment. You can configure Poetry to use an in-project virtual environment by running:\n\n```bash\npoetry config virtualenvs.in-project true\n```\n\n### Running Tests\n\n```bash\npoetry run pytest\n```\n\n## Contributing\n\n1. Fork the repository.\n2. Create a branch named `feature/your_feature`.\n3. Commit your changes, push, and submit a pull request.\n\nThanks for contributing!\n\n## Contributors\n\n\u003ca href=\"https://github.com/sonic182/aiosonic/graphs/contributors\"\u003e\n \u003cimg src=\"https://contributors-img.web.app/image?repo=sonic182/aiosonic\" alt=\"Contributors\" /\u003e\n\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsonic182%2Faiosonic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsonic182%2Faiosonic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsonic182%2Faiosonic/lists"}