aiodns
aiodns is a Python library that provides a simple way to perform asynchronous DNS resolutions using the `asyncio` framework and `pycares` as its backend. The current version is 4.0.0, and it generally follows an active release cadence with several updates throughout the year to improve performance, add features, and maintain compatibility with newer Python and `pycares` versions.
Warnings
- breaking Version 4.0.0 introduces a breaking change requiring `pycares >= 5.0.0`. Older `pycares` versions are incompatible and will cause issues.
- deprecated The `query()` method is deprecated in favor of `query_dns()`. While `query()` still works for backward compatibility with `aiodns 3.x` result types, `query_dns()` returns native `pycares 5.x DNSResult` types which are preferred.
- deprecated The `gethostbyname()` method is deprecated. Use `getaddrinfo()` instead for host and port resolution.
- gotcha `DNSResolver` instances are designed to be long-lived and reused across many queries to avoid unnecessary overhead. While `DNSResolver` supports the async context manager (`async with DNSResolver()`), using it for frequent, short-lived instances is discouraged due to performance implications. It's best suited for testing or one-off scripts where automatic cleanup is critical.
- gotcha On Windows, if you are using a custom build of `pycares` that links against a non-thread-safe `c-ares` library, `aiodns` might require `asyncio.SelectorEventLoop` or `winloop`. This is generally not an issue for users of official prebuilt `pycares` wheels (version 4.7.0 or later), as they include a thread-safe `c-ares`.
Install
-
pip install aiodns
Imports
- DNSResolver
from aiodns import DNSResolver
- DNSError
from aiodns import error
Quickstart
import asyncio
from aiodns import DNSResolver
async def resolve_a_record(hostname):
resolver = DNSResolver()
try:
# query_dns returns native pycares 5.x DNSResult types
result = await resolver.query_dns(hostname, 'A')
for record in result.answer:
print(f"Hostname: {hostname}, Type: A, Address: {record.data.addr}")
except Exception as e:
print(f"DNS resolution failed for {hostname}: {e}")
finally:
# It's important to close the resolver when no longer needed.
# For long-lived resolvers, manual closing is often done at application shutdown.
resolver.close()
async def main():
await resolve_a_record('google.com')
await resolve_a_record('nonexistent.example.com') # Example of a failed lookup
if __name__ == '__main__':
asyncio.run(main())