Skip to main content

py-doh-core

Python bindings for doh-core, a Rust DNS resolver library that only speaks secure transports — DNS-over-HTTPS (RFC 8484), DNS-over-TLS (RFC 7858), and DNS-over-QUIC (RFC 9250) — with no fallback to classic plaintext DNS. If a query can't be answered securely, you get a clear exception instead of a silent, unencrypted lookup.

pip install py-doh-core

Quickstart

import py_doh_core as doh

transport = doh.DohTransport("https://dns.google/dns-query")
response = transport.resolve("example.com", "A")

for answer in response.answers:
    print(answer.name, answer.ttl, answer.rdata)

Every resolve() has an async def-compatible aresolve() twin:

import asyncio
import py_doh_core as doh


async def main() -> None:
    transport = doh.DotTransport("dns.google")
    response = await transport.aresolve("example.com", "AAAA")
    print(response.answers[0].rdata)


asyncio.run(main())

resolve() blocks the calling thread but releases the GIL for the network call, so other Python threads keep running; aresolve() returns a normal awaitable. Both forms exist on all three transports below.

Transports

Class Protocol Constructor
DohTransport DNS-over-HTTPS DohTransport(server_url, method=None)server_url e.g. "https://dns.google/dns-query" (must be https://); method is "get" (default) or "post"
DotTransport DNS-over-TLS DotTransport(server_addr)server_addr is host[:port], default port 853
DoqTransport DNS-over-QUIC DoqTransport(server_addr) — same host[:port] form; the QUIC connection is pooled and reused across every resolve()/aresolve() call on the instance

All three share the same API: resolve, aresolve, resolve_many, aresolve_many. Pick a transport, not a different way of calling it.

Responses are typed, not dicts

resolve()/aresolve() return a ParsedResponse with real attributes — response.answers[0].rdata, not response["answers"][0]["rdata"] — mirroring every field of the underlying doh_core::ParsedResponse (header flags, question, answer/authority/additional sections, wire size). op_code and response_code are OpCode/ResponseCode enums, not magic strings or ints:

if response.response_code == doh.ResponseCode.NXDOMAIN:
    ...  # the name doesn't exist -- this is a successful response, not an error

See py_doh_core.pyi for the full type signatures.

Handling errors

Anything that isn't a clean "no error" or "name does not exist" response — a bad server URL, a connection failure, SERVFAIL, REFUSED, a malformed reply — raises doh.DohError rather than returning a half-empty result:

try:
    response = transport.resolve("dnssec-failed.org", "A")
except doh.DohError as exc:
    print("lookup failed:", exc)

str(exc) carries the same message the underlying Rust library produces.

Multiple record types in one call

resolve_many()/aresolve_many() query several record types for one name against a single transport instance. Queries run in turn, reusing the connection where that matters (DoqTransport's pooled connection in particular), and one type's failure doesn't abort the rest — each entry in the returned list is a QueryResult with exactly one of response/error set:

for result in transport.resolve_many("example.com", ["A", "AAAA", "MX"]):
    if result.error is not None:
        print(result.record_type, "failed:", result.error)
    else:
        print(result.record_type, [a.rdata for a in result.response.answers])

An unparseable record type string is the one exception: it raises DohError immediately, before any query in the batch is sent.

Logging

Verbose/debug output uses Python's standard logging module — no separate init call needed:

import logging

logging.basicConfig(level=logging.DEBUG)

Logger names follow the Rust module path, e.g. doh_core.transport.doh, doh_core.transport.doq, py_doh_core.transport. DEBUG shows one line per query (server, method, connection reuse, response codes); a small amount of extra detail (e.g. response sizes) logs at level 5, below logging.DEBUG (10) — pass level=5 to see it. Scope to just this library with logging.getLogger("doh_core").setLevel(logging.DEBUG).

Only doh_core/py_doh_core targets are bridged to Python — dependency crates (reqwest, h2, rustls, quinn) are deliberately not, since their logging runs on long-lived background threads that can outlive a single resolve() call and, in rare cases, still be active as the Python interpreter shuts down.

Development

py-doh-core is a PyO3 cdylib extension module, built with maturin. It's intentionally excluded from the main Cargo workspace (see the root Cargo.toml) since it needs maturin's linker setup to resolve Python symbols at import time — plain cargo build/cargo test --workspace can't link it.

Build from source

cd py-doh-core
python3 -m venv .venv
source .venv/bin/activate
pip install maturin
maturin develop

Tests

pip install pytest pytest-asyncio
pytest

tests/test_resolve.py runs live against real public resolvers (no mocking layer, same approach the Rust side uses). DoT/DoQ cases skip automatically if port 853 is unreachable on the current network.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py_doh_core-0.1.1.tar.gz (82.8 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

py_doh_core-0.1.1-cp39-abi3-win_amd64.whl (3.1 MB view details)

Uploaded CPython 3.9+Windows x86-64

py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.9 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file py_doh_core-0.1.1.tar.gz.

File metadata

  • Download URL: py_doh_core-0.1.1.tar.gz
  • Upload date:
  • Size: 82.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for py_doh_core-0.1.1.tar.gz
Algorithm Hash digest
SHA256 469166eac33639a08abf4b809ef1499c70185ea401e0c8340b224111d13a6684
MD5 bdaa95d0f62eeea31c8fd3d4c816dcb5
BLAKE2b-256 82c1ca80dec7fb696e8a9e2a2bfba7d9fe77b4a4220eacaf1e87ae84311911d0

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_doh_core-0.1.1.tar.gz:

Publisher: py-doh-core-release.yml on ubahmapk/doh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_doh_core-0.1.1-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: py_doh_core-0.1.1-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 3.1 MB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for py_doh_core-0.1.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 297d83e182c306796c9ab889b35aaefaeef13c55bba6902529d80e5f550ba67e
MD5 3bf3d4903189a7196db59d5d9e0ee527
BLAKE2b-256 a605c723b966676b5891ec4b82b4cff1d9ff5fe0f3bd5878f0018985f5d2c055

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-win_amd64.whl:

Publisher: py-doh-core-release.yml on ubahmapk/doh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ff49d082aeda195ef7d52b52de4a8b9a7476c339b95cbc29e8e09db0933473db
MD5 35008ba3c00021a58c58fec5068f8d3c
BLAKE2b-256 262c6d2064f43a8bfe92bd2d944a062ee3117fb3217e356d0fa7bb905d65ca00

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: py-doh-core-release.yml on ubahmapk/doh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f7c31b03ed2fa3db3b7325c2c8ac23bcd1ca54be07bc8dcf8cab322a4c0ab879
MD5 7632925b8179e7a465125897de4fb80f
BLAKE2b-256 44d3d9a38b29d9a302bd113dbf8a805850edfed601f5760bedbe0e30eb6248e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: py-doh-core-release.yml on ubahmapk/doh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fba80694184d11f6e906931ec466c8b0cc2cba98f8547ac7db2059cb316a6d2c
MD5 cd1e8684a9a58affaf38676ebca1e54c
BLAKE2b-256 60910bbaec28e2b04f4e5ea3f389ea6abde04874b55e05086acf86b44687e790

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: py-doh-core-release.yml on ubahmapk/doh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 a05f47e3b1f6fe5c7f3ca30f5aa9b2eb99e6813535b1fbaec17f67505496e874
MD5 7e05e9c28078c8f4dfc18d761ca61cdc
BLAKE2b-256 0e918eeed73d9f3d897e63d1a3472d60802af31fc5a2862c26d5bd335cc4f982

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_doh_core-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: py-doh-core-release.yml on ubahmapk/doh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.1 This release

6 files

0.1.0

6 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page