Skip to content

Commit 2a65ab2

Browse files
authored
Add pycares 5.0 support with backward-compatible result types (#218)
1 parent 0fd88aa commit 2a65ab2

9 files changed

Lines changed: 1710 additions & 193 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,7 @@ jobs:
5959
strategy:
6060
matrix:
6161
os: [ubuntu-latest, windows-latest, macos-latest]
62-
python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13', '3.14' ]
63-
exclude:
64-
- os: macos-latest
65-
python-version: 3.9
66-
include:
67-
- python-version: pypy-3.9
68-
os: ubuntu-latest
62+
python-version: [ '3.10', '3.11', '3.12', '3.13', '3.14', '3.14t' ]
6963
timeout-minutes: 15
7064
steps:
7165
- name: Checkout

README.rst

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,13 @@ Example
1919
import asyncio
2020
import aiodns
2121
22-
loop = asyncio.get_event_loop()
23-
resolver = aiodns.DNSResolver(loop=loop)
22+
async def main():
23+
resolver = aiodns.DNSResolver()
24+
result = await resolver.query_dns('google.com', 'A')
25+
for record in result.answer:
26+
print(record.data.addr)
2427
25-
async def query(name, query_type):
26-
return await resolver.query(name, query_type)
27-
28-
coro = query('google.com', 'A')
29-
result = loop.run_until_complete(coro)
28+
asyncio.run(main())
3029
3130
3231
The following query types are supported: A, AAAA, ANY, CAA, CNAME, MX, NAPTR, NS, PTR, SOA, SRV, TXT.
@@ -37,27 +36,66 @@ API
3736

3837
The API is pretty simple, the following functions are provided in the ``DNSResolver`` class:
3938

40-
* ``query(host, type)``: Do a DNS resolution of the given type for the given hostname. It returns an
41-
instance of ``asyncio.Future``. The actual result of the DNS query is taken directly from pycares.
42-
As of version 1.0.0 of aiodns (and pycares, for that matter) results are always namedtuple-like
43-
objects with different attributes. Please check the `documentation
44-
<http://pycares.readthedocs.org/latest/channel.html#pycares.Channel.query>`_
45-
for the result fields.
46-
* ``gethostbyname(host, socket_family)``: Do a DNS resolution for the given
47-
hostname and the desired type of address family (i.e. ``socket.AF_INET``).
48-
While ``query()`` always performs a request to a DNS server,
49-
``gethostbyname()`` first looks into ``/etc/hosts`` and thus can resolve
50-
local hostnames (such as ``localhost``). Please check `the documentation
51-
<http://pycares.readthedocs.io/latest/channel.html#pycares.Channel.gethostbyname>`_
52-
for the result fields. The actual result of the call is a ``asyncio.Future``.
39+
* ``query_dns(host, type)``: Do a DNS resolution of the given type for the given hostname. It returns an
40+
instance of ``asyncio.Future``. The result is a ``pycares.DNSResult`` object with ``answer``,
41+
``authority``, and ``additional`` attributes containing lists of ``pycares.DNSRecord`` objects.
42+
Each record has ``type``, ``ttl``, and ``data`` attributes. Check the `pycares documentation
43+
<https://pycares.readthedocs.io/>`_ for details on the data attributes for each record type.
44+
* ``query(host, type)``: **Deprecated** - use ``query_dns()`` instead. This method returns results
45+
in a legacy format compatible with aiodns 3.x for backward compatibility.
46+
* ``gethostbyname(host, socket_family)``: **Deprecated** - use ``getaddrinfo()`` instead.
47+
Do a DNS resolution for the given hostname and the desired type of address family
48+
(i.e. ``socket.AF_INET``). The actual result of the call is a ``asyncio.Future``.
5349
* ``gethostbyaddr(name)``: Make a reverse lookup for an address.
50+
* ``getaddrinfo(host, family, port, proto, type, flags)``: Resolve a host and port into a list of
51+
address info entries.
52+
* ``getnameinfo(sockaddr, flags)``: Resolve a socket address to a host and port.
5453
* ``cancel()``: Cancel all pending DNS queries. All futures will get ``DNSError`` exception set, with
5554
``ARES_ECANCELLED`` errno.
5655
* ``close()``: Close the resolver. This releases all resources and cancels any pending queries. It must be called
5756
when the resolver is no longer needed (e.g., application shutdown). The resolver should only be closed from the
5857
event loop that created the resolver.
5958

6059

60+
Migrating from aiodns 3.x
61+
=========================
62+
63+
aiodns 4.x introduces a new ``query_dns()`` method that returns native pycares 5.x result types.
64+
See the `pycares documentation <https://pycares.readthedocs.io/latest/channel.html#pycares.Channel.query>`_
65+
for details on the result types. The old ``query()`` method is deprecated but continues to work
66+
for backward compatibility.
67+
68+
.. code:: python
69+
70+
# Old API (deprecated)
71+
result = await resolver.query('example.com', 'MX')
72+
for record in result:
73+
print(record.host, record.priority)
74+
75+
# New API (recommended)
76+
result = await resolver.query_dns('example.com', 'MX')
77+
for record in result.answer:
78+
print(record.data.exchange, record.data.priority)
79+
80+
81+
Future migration to aiodns 5.x
82+
------------------------------
83+
84+
The temporary ``query_dns()`` naming allows gradual migration without breaking changes:
85+
86+
+-----------+---------------------------------------+--------------------------------------------+
87+
| Version | ``query()`` | ``query_dns()`` |
88+
+===========+=======================================+============================================+
89+
| **4.x** | Deprecated, returns compat types | New API, returns pycares 5.x types |
90+
+-----------+---------------------------------------+--------------------------------------------+
91+
| **5.x** | New API, returns pycares 5.x types | Alias to ``query()`` for back compat |
92+
+-----------+---------------------------------------+--------------------------------------------+
93+
94+
In aiodns 5.x, ``query()`` will become the primary API returning native pycares 5.x types,
95+
and ``query_dns()`` will remain as an alias for backward compatibility. This allows downstream
96+
projects to migrate at their own pace.
97+
98+
6199
Async Context Manager Support
62100
=============================
63101

@@ -67,7 +105,7 @@ for scenarios where automatic cleanup is desired:
67105
.. code:: python
68106
69107
async with aiodns.DNSResolver() as resolver:
70-
result = await resolver.query('example.com', 'A')
108+
result = await resolver.query_dns('example.com', 'A')
71109
# resolver.close() is called automatically when exiting the context
72110
73111
**Important**: This pattern is discouraged for most applications because ``DNSResolver`` instances
@@ -101,7 +139,7 @@ This may have other implications for the rest of your codebase, so make sure to
101139
Running the test suite
102140
======================
103141

104-
To run the test suite: ``python tests.py``
142+
To run the test suite: ``python -m pytest tests/``
105143

106144

107145
Author

0 commit comments

Comments
 (0)