# 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):

    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):

    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 `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 `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:

- `ARecordData`: `addr` (IPv4 address)

- `AAAARecordData`: `addr` (IPv6 address)

- `MXRecordData`: `priority`, `exchange`

- `TXTRecordData`: `data` (bytes)

- `CAARecordData`: `critical`, `tag`, `value`

- `CNAMERecordData`: `cname`

- `NAPTRRecordData`: `order`, `preference`, `flags`, `service`, `regexp`, `replacement`

- `NSRecordData`: `nsdname`

- `PTRRecordData`: `dname`

- `SOARecordData`: `mname`, `rname`, `serial`, `refresh`, `retry`, `expire`, `minimum`

- `SRVRecordData`: `priority`, `weight`, `port`, `target`

- `TLSARecordData`: `cert_usage`, `selector`, `matching_type`, `cert_association_data`

- `HTTPSRecordData`: `priority`, `target`, `params`

- `URIRecordData`: `priority`, `weight`, `target`

### Channel Constructor Arguments Are Keyword-Only

All `Channel` constructor arguments must now be passed as keyword arguments.

Before (4.x):

    # Positional arguments worked
    channel = pycares.Channel(0, 5.0, 4, 1)

After (5.0):

    # 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 `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):

    # 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):

    # 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):

    channel.query("example.com", pycares.QUERY_TYPE_A, my_callback)

After (5.0):

    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):

    channel.gethostbyname("example.com", socket.AF_INET, callback)

After (5.0):

    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):

    read_fds, write_fds = channel.getsock()
    # Manual polling of file descriptors

After (5.0):

    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):

    for record in result:
        print(record.text)  # str

After (5.0):

    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

    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:

    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