1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
|
.. _migration:
*******************************
Migrating to pycares 5.0
*******************************
pycares 5.0 is a major release with significant API changes. This guide
covers all breaking changes and how to update your code.
Breaking Changes
================
DNS Query Results API
---------------------
The DNS query API has been completely rewritten. Query results now use
structured dataclasses instead of the previous format.
**Before (4.x):**
.. code-block:: python
def callback(result, error):
if error:
print(f"Error: {error}")
return
# result was a list of record-specific objects
for record in result:
print(record.host) # A record example
channel.query("example.com", pycares.QUERY_TYPE_A, callback)
**After (5.0):**
.. code-block:: python
def callback(result, error):
if error:
print(f"Error: {error}")
return
# result is now a DNSResult with answer/authority/additional sections
for record in result.answer:
print(f"{record.name} TTL={record.ttl}: {record.data.addr}")
channel.query("example.com", pycares.QUERY_TYPE_A, callback=callback)
The new :class:`DNSResult` dataclass contains three sections:
- ``answer``: List of answer records (the main query results)
- ``authority``: List of authority records (nameserver information)
- ``additional``: List of additional records
Each record is a :class:`DNSRecord` dataclass with:
- ``name``: Domain name (str)
- ``type``: Record type constant (int)
- ``record_class``: Record class, typically ``QUERY_CLASS_IN`` (int)
- ``ttl``: Time to live in seconds (int)
- ``data``: Type-specific dataclass with the record content
Record data types:
- :class:`ARecordData`: ``addr`` (IPv4 address)
- :class:`AAAARecordData`: ``addr`` (IPv6 address)
- :class:`MXRecordData`: ``priority``, ``exchange``
- :class:`TXTRecordData`: ``data`` (bytes)
- :class:`CAARecordData`: ``critical``, ``tag``, ``value``
- :class:`CNAMERecordData`: ``cname``
- :class:`NAPTRRecordData`: ``order``, ``preference``, ``flags``, ``service``, ``regexp``, ``replacement``
- :class:`NSRecordData`: ``nsdname``
- :class:`PTRRecordData`: ``dname``
- :class:`SOARecordData`: ``mname``, ``rname``, ``serial``, ``refresh``, ``retry``, ``expire``, ``minimum``
- :class:`SRVRecordData`: ``priority``, ``weight``, ``port``, ``target``
- :class:`TLSARecordData`: ``cert_usage``, ``selector``, ``matching_type``, ``cert_association_data``
- :class:`HTTPSRecordData`: ``priority``, ``target``, ``params``
- :class:`URIRecordData`: ``priority``, ``weight``, ``target``
Channel Constructor Arguments Are Keyword-Only
----------------------------------------------
All :class:`Channel` constructor arguments must now be passed as keyword arguments.
**Before (4.x):**
.. code-block:: python
# Positional arguments worked
channel = pycares.Channel(0, 5.0, 4, 1)
**After (5.0):**
.. code-block:: python
# All arguments must be keyword arguments
channel = pycares.Channel(flags=0, timeout=5.0, tries=4, ndots=1)
event_thread Parameter Removed
------------------------------
The ``event_thread`` parameter has been removed from the :class:`Channel`
constructor. Event thread mode is now implicit:
- If ``sock_state_cb`` is **not** provided: event thread mode is automatically enabled
- If ``sock_state_cb`` **is** provided: manual event loop integration is assumed
**Before (4.x):**
.. code-block:: python
# Explicit event thread mode
channel = pycares.Channel(event_thread=True)
# Or with sock_state_cb for manual mode
channel = pycares.Channel(sock_state_cb=my_callback, event_thread=False)
**After (5.0):**
.. code-block:: python
# Event thread mode (automatic when no sock_state_cb)
channel = pycares.Channel()
# Manual event loop integration
channel = pycares.Channel(sock_state_cb=my_callback)
callback Parameter Is Mandatory and Keyword-Only
------------------------------------------------
The ``callback`` parameter for query methods must now be explicitly provided
as a keyword argument.
**Before (4.x):**
.. code-block:: python
channel.query("example.com", pycares.QUERY_TYPE_A, my_callback)
**After (5.0):**
.. code-block:: python
channel.query("example.com", pycares.QUERY_TYPE_A, callback=my_callback)
Removed Functions
-----------------
gethostbyname()
^^^^^^^^^^^^^^^
The ``gethostbyname()`` method has been removed. Use ``getaddrinfo()`` instead.
**Before (4.x):**
.. code-block:: python
channel.gethostbyname("example.com", socket.AF_INET, callback)
**After (5.0):**
.. code-block:: python
channel.getaddrinfo(
host="example.com",
port=None,
family=socket.AF_INET,
callback=callback
)
getsock()
^^^^^^^^^
The ``getsock()`` method has been removed. Use ``sock_state_cb`` for event
loop integration or rely on the automatic event thread mode.
**Before (4.x):**
.. code-block:: python
read_fds, write_fds = channel.getsock()
# Manual polling of file descriptors
**After (5.0):**
.. code-block:: python
def sock_state_cb(fd, readable, writable):
# Register/unregister fd with your event loop
pass
channel = pycares.Channel(sock_state_cb=sock_state_cb)
Or simply use event thread mode by not providing ``sock_state_cb``.
TXT Records Return Bytes
------------------------
TXT record data is now returned as ``bytes`` instead of ``str``.
**Before (4.x):**
.. code-block:: python
for record in result:
print(record.text) # str
**After (5.0):**
.. code-block:: python
for record in result.answer:
print(record.data.data) # bytes
print(record.data.data.decode()) # decode if needed
New Features
============
New Query Types
---------------
pycares 5.0 adds support for new DNS record types:
- ``QUERY_TYPE_TLSA``: DANE TLSA records for certificate association
- ``QUERY_TYPE_HTTPS``: HTTPS service binding records
- ``QUERY_TYPE_URI``: URI records
.. code-block:: python
channel.query("_443._tcp.example.com", pycares.QUERY_TYPE_TLSA, callback=callback)
channel.query("example.com", pycares.QUERY_TYPE_HTTPS, callback=callback)
channel.query("example.com", pycares.QUERY_TYPE_URI, callback=callback)
Channel.wait() Method
---------------------
A new ``wait()`` method allows waiting for all pending queries to complete:
.. code-block:: python
channel = pycares.Channel()
channel.query("example.com", pycares.QUERY_TYPE_A, callback=callback)
channel.query("example.com", pycares.QUERY_TYPE_AAAA, callback=callback)
# Wait for all queries to complete (with optional timeout in seconds)
channel.wait(timeout=10.0)
Build System Changes
====================
CMake Required
--------------
pycares now uses CMake to build the bundled c-ares library. Ensure CMake >= 3.5
is installed:
- Ubuntu/Debian: ``apt-get install cmake``
- macOS: ``brew install cmake``
- Windows: Download from https://cmake.org/download/
Thread Safety Mandatory
-----------------------
c-ares is now always built with thread safety enabled. This is required for
the implicit event thread mode and ensures safe operation in multi-threaded
applications.
Quick Migration Checklist
=========================
1. Update all query callbacks to handle the new ``DNSResult`` dataclass format
2. Change all ``Channel()`` calls to use keyword arguments
3. Remove any ``event_thread=True/False`` parameters
4. Add ``callback=`` keyword to all query/search method calls
5. Replace ``gethostbyname()`` with ``getaddrinfo()``
6. Remove ``getsock()`` usage; use ``sock_state_cb`` or event thread mode
7. Update TXT record handling to expect ``bytes`` instead of ``str``
8. Ensure CMake >= 3.5 is installed for building from source
|