{"id":29569198,"url":"https://github.com/vizonex/cyares","last_synced_at":"2026-05-13T03:15:08.312Z","repository":{"id":299496043,"uuid":"1003087265","full_name":"Vizonex/cyares","owner":"Vizonex","description":"An Upgraded version of pycares with faster and safer features.","archived":false,"fork":false,"pushed_at":"2026-01-22T03:14:32.000Z","size":474,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-22T16:23:11.062Z","etag":null,"topics":["asyncio","c-ares","cython","dns","dnsresolver","pycares","trio"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/cyares","language":"Cython","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/Vizonex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-16T15:48:30.000Z","updated_at":"2026-01-22T03:14:29.000Z","dependencies_parsed_at":"2025-06-16T21:37:58.903Z","dependency_job_id":"0d7bea3f-13d8-42bb-9b63-ddd9f08df2d2","html_url":"https://github.com/Vizonex/cyares","commit_stats":null,"previous_names":["vizonex/_cyares","vizonex/cyares"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/Vizonex/cyares","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vizonex%2Fcyares","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vizonex%2Fcyares/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vizonex%2Fcyares/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vizonex%2Fcyares/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vizonex","download_url":"https://codeload.github.com/Vizonex/cyares/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vizonex%2Fcyares/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29130580,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T18:55:47.139Z","status":"ssl_error","status_checked_at":"2026-02-05T18:55:04.010Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","c-ares","cython","dns","dnsresolver","pycares","trio"],"created_at":"2025-07-19T01:38:45.704Z","updated_at":"2026-02-05T19:34:15.914Z","avatar_url":"https://github.com/Vizonex.png","language":"Cython","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"https://raw.githubusercontent.com/Vizonex/cyares/main/Cy-Ares-Logo.png\"/\u003e\r\n\r\n[![PyPI version](https://badge.fury.io/py/cyares.svg)](https://badge.fury.io/py/cyares)\r\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/cyares)](https://badge.fury.io/py/cyares)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\r\n\r\nAn Upgraded version of __pycares__ with faster and safer features.\r\n\r\n# Installation\r\n\r\n## How to install\r\n```\r\npip install cyares\r\n```\r\n\r\n## How to install with Trio bundle\r\n```\r\npip install cyares[trio]\r\n```\r\n\r\n## How to install with anyio bundle\r\n```\r\npip install cyares[anyio]\r\n```\r\n\r\n## How to install with optional IDNA Plugin\r\n```\r\npip install cyares[idna]\r\n```\r\n\r\n## How to install with optional aiohttp extension\r\n```\r\npip install cyares[aiohttp]\r\n```\r\n\r\n## Installing all bundles\r\n```\r\npip install cyares[all]\r\n```\r\n\r\n\r\n# Small Examples of How to Use\r\n\r\n```python\r\nfrom cyares import Channel\r\n\r\n# NOTE: Dns Queries contain a Future object\r\n# This is a little bit different from pycares \r\n# Handles were used to prevent new or unwanted vulnerabilities along\r\n# with easier control given to the user...\r\n# The Future object comes from the python concurrent.futures standard library\r\n\r\ndef main():\r\n    with Channel(servers=[\"8.8.8.8\", \"8.8.4.4\"], event_thread=True) as channel:\r\n        data = channel.query(\"google.com\", \"A\").result()\r\n    print(data)\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n```\r\n\r\n## In Asyncio\r\nThere's a module for an **aiodns** version if aiodns were using cyares.\r\n\r\n```python\r\nimport winloop # or uvloop (asyncio will also work) \r\nfrom cyares.aio import DNSResolver\r\n\r\nasync def test():\r\n    async with DNSResolver([\"8.8.8.8\", \"8.8.4.4\"]) as dns:\r\n        data = await dns.query(\"google.com\", \"A\")\r\n    print(data)\r\n\r\nif __name__ == \"__main__\":\r\n    winloop.run(test())\r\n```\r\n\r\n## Trio\r\nTrio is now supported as well which means this library is not just limited to \r\nsynchronous python or asyncio. \r\n\r\n```python\r\nfrom cyares.trio import DNSResolver\r\nimport trio\r\n\r\nasync def test():\r\n    async with DNSResolver([\"8.8.8.8\", \"8.8.4.4\"], rotate=True, event_thread=False) as dns:\r\n        result = await dns.query(\"google.com\", \"A\")\r\n        print(result)\r\n\r\nif __name__ == \"__main__\":\r\n    trio.run(test)\r\n```\r\n\r\n## Anyio\r\nAs of `0.4.0` anyio is now supported if you need use an anyio implementation\r\n```python\r\nfrom cyares.anyio import DNSResolver\r\nimport anyio\r\n\r\nasync def test():\r\n    async with DNSResolver([\"8.8.8.8\", \"8.8.4.4\"], rotate=True, event_thread=False) as dns:\r\n        result = await dns.query(\"google.com\", \"A\")\r\n        print(result)\r\n\r\nif __name__ == \"__main__\":\r\n    anyio.run(test)\r\n```\r\n\r\n# Aiohttp\r\n## Using Globally (Monkey Patch Method)\r\n\r\n\u003e[!WARNING]\r\n\u003e aiohttp implementation is still buggy. Use at your own risk.\r\n\r\n`install()` applies a monkeypatch globally\r\nKnow that if you wanted to use different resolvers with\r\naiohttp you can do that by passing `CyAresResolver` through to the\r\n`ClientSession`. another way to avoid `install()` not being threadsafe is by\r\ninstalling before the rest of your code begins running.\r\nSame as how **uvloop** and **winloop** both work\r\n\r\n```python\r\nfrom cyares.aiohttp import install\r\nfrom aiohttp import ClientSession\r\nimport asyncio\r\n\r\nasync def main():\r\n    # CyAres should be monkeypatched to be the default \r\n    # DNS Resolver for this http request\r\n    async with ClientSession() as client:\r\n        async with client.get(\"https://httpbin.org/ip\") as result:\r\n            data = await result.json()\r\n            print(f'YOUR IP ADDRESS IS: {data[\"origin\"]}')\r\n\r\nif __name__ == \"__main__\":\r\n    install()\r\n    asyncio.run(main())\r\n```\r\n\r\nwhen your done with an evenloop run and want to rerun\r\nanother but with an alternate dnsresolver such as **aiodns**\r\nor the `ThreadedResolver` use `uninstall()`\r\n\r\n# Using Non-Globally\r\n\r\nAlthough slightly more tricky it is possible to pass along `CyAresResolver`\r\nwith the right setup without resorting to `install()`. This will also\r\nwork with aiohttp_socks or using aiohttp_socks with a proxy or tor or i2p.\r\nIf you feel uncomfortable with sending this much stuff to `ClientSession`\r\nyourself it's encouraged to use globally with `install()` or via\r\nmonkeypatching aiohttp's default dns resolver in your own way.\r\n\r\n```python\r\n\r\nfrom cyares.aiohttp import CyAresResolver\r\nfrom aiohttp import ClientSession, TCPConnector\r\n\r\n# NOTE: This should also be respected when aiohttp_socks is in use\r\n# Such as the ProxyConnector which is another connector type of it's\r\n# own\r\n\r\nasync def main():\r\n    async with ClientSession(\r\n        connector=TCPConnector(CyAresResolver()\r\n    )) as client:\r\n        async with client.get(\"https://httpbin.org/ip\") as result:\r\n            data = await result.json()\r\n            print(f'YOUR IP ADDRESS IS: {data[\"origin\"]}')\r\n```\r\n\r\n## In Cython\r\n```cython\r\nfrom cyares cimport Channel, Future, AresError\r\n\r\n\r\ndef dns_resolve_a(str domain):\r\n    \"\"\"Resolves IPV4 Using cython\"\"\"\r\n    cdef Future fut\r\n    with Channel(['8.8.8.8', '8.8.4.4'], event_thread=True) as   channel:\r\n        fut = cannel.query(domain, \"A\")\r\n    return fut.wait()\r\n```\r\n\r\n\r\n## Story\r\nAs Someone who as recently started to contribute to projects such as __aiohttp__ and a few of it's smaller libraries. The asynchronous dns resolver __aiodns__ that __aiohttp__ can optionally use, felt like the oddest one in the group. With __aiodns__ using __pycares__ under the hood I wanted to learn how it worked to see if I could use my skills to optimize it like I had previously done with __propcache__ and __multidict__ as well but I soon came to learn of it's many problems and when __pycares__ started to hang on me with lingering threads when it ran, something didn't feel right to me and it lead me down a very large rabbit-hole waiting to be re-explored.\r\n\r\n__Pycares__ was quick, dirty and fast but as the years of it's existance went by something wasn't exactly right with it and it could use safer features, better optimization and safety practices. While __cffi__ might be both quick and easy to use I didn't see the benefit of using it. The many vulnerabilities it was getting told me something needed to change if not big. With __Pycares__ reaching version __5.0.0__ I wanted to celebrate it the same way node-js celebrated the 10 year annversery of the original __http-parser__. Write a new one.\r\n\r\n\r\n### The Rewrite \r\n\r\nWhile contributing to the aio-libs repos whenever I had a gap of free-time on hand while waiting on a question to be answered and when my other python libraries felt stable enough such as (deprecated-params, aiocallback, aiothreading \u0026 winloop) this is where I spent my time on. It had a total of 3 re-writes until I was satisfied with the result. Turns out just doing everything in small chunks makes all the difference. \r\n\r\nIt only felt right to me that migrating the library from __cffi__ to __cython__ would be the best solution to the problem. Not __Rust__ or __C__, just __pure-cython__ and small amounts of __C__ whenever nessesary and re-changing many of the internals to incorperate a safer approch. The reason for not picking __Rust__ is that there wasn't nessesarly a need to be memory-safe. What I cared about was speed, when people are doing DNS Lookups, speed matters and __Rust__ did not have a friendly enough archetecture that would set a future or allow me to access the parent from the child. \r\n\r\nThere was no better canadate than to move to using handles the same way __uvloop__ \u0026 __winloop__ do it and having authored one of them I was familliar with this concept.\r\n\r\nThe idea was not to reinvent the wheel rather move parts of the library over in chunks and look at __pycares__ for clues on how certain things should be laid out. At the end of the day, __Pycares__ was the blueprint and using __concurrent.futures__ \u0026 __Cython__ was the cure. __Py_buffer__ techniques brought over from __msgspec__ were utilized incase users were planning to use any bytes or string objects of any sort and I made sure the license was on it incase users wanted to know where it came from.\r\n\r\nIf there was a deprecated function with an alternative \u0026 safer approch to use I felt using it would be a better move. For example, servers are now set with the csv functions rather than the original setup and because of that change you could now set dns servers in url formats and I might possibly look at adding in __yarl__ to be the cherry on top for those who might wish to get real creative about dns server urls. \r\n\r\nMoving over the __ares_query__ function to use the dns recursion function is planned for the future (maybe after I do the first release of cyares). I still wanted to retain the original response data it gives so that migrating from __pycares__ to __cyares__ wouldn't be a pain to anyone who planned on moving and I also didn't want to take away from __pycares__ either if you prefer using __cffi__ over __cython__ the same way __curl-cffi__ and __cycurl__ were both done. I have my fingers crossed that __aiodns__ will adopt this library in the future or allow users to choose between __pycares__ and __cyares__.\r\n\r\n\r\n\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvizonex%2Fcyares","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvizonex%2Fcyares","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvizonex%2Fcyares/lists"}