From: Bob Halley Date: Sun, 12 Apr 2026 17:43:45 +0000 (-0700) Subject: Comprehensive conversion of documentation to Python documentation norms. (#1266) X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=d2b3f457a62951afdc7c43aa2ab815676317b63a;p=thirdparty%2Fdnspython.git Comprehensive conversion of documentation to Python documentation norms. (#1266) --- diff --git a/dns/asyncbackend.py b/dns/asyncbackend.py index 831ec6e9..2b3cf4d6 100644 --- a/dns/asyncbackend.py +++ b/dns/asyncbackend.py @@ -27,10 +27,10 @@ class AsyncLibraryNotFoundError(dns.exception.DNSException): def get_backend(name: str) -> Backend: """Get the specified asynchronous backend. - *name*, a ``str``, the name of the backend. Currently the "trio" - and "asyncio" backends are available. - - Raises NotImplementedError if an unknown backend name is specified. + :param name: The name of the backend. Currently ``"trio"`` and + ``"asyncio"`` are available. + :type name: str + :raises NotImplementedError: If an unknown backend name is specified. """ # pylint: disable=import-outside-toplevel,redefined-outer-name backend = _backends.get(name) diff --git a/dns/asyncquery.py b/dns/asyncquery.py index 986a37a5..e6ab2e3d 100644 --- a/dns/asyncquery.py +++ b/dns/asyncquery.py @@ -96,19 +96,18 @@ async def send_udp( ) -> tuple[int, float]: """Send a DNS message to the specified UDP socket. - *sock*, a ``dns.asyncbackend.DatagramSocket``. - - *what*, a ``bytes`` or ``dns.message.Message``, the message to send. - - *destination*, a destination tuple appropriate for the address family - of the socket, specifying where to send the query. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. The expiration value is meaningless for the asyncio backend, as - asyncio's transport sendto() never blocks. - - Returns an ``(int, float)`` tuple of bytes sent and the sent time. + :param sock: The socket to use. + :type sock: :py:class:`dns.asyncbackend.DatagramSocket` + :param what: The message to send. + :type what: bytes or :py:class:`dns.message.Message` + :param destination: A destination tuple appropriate for the address + family of the socket. + :param expiration: The absolute time at which to raise a timeout + exception. ``None`` means no timeout (and is meaningless for the + asyncio backend, as ``sendto()`` never blocks there). + :type expiration: float or ``None`` + :returns: A ``(bytes_sent, sent_time)`` tuple. + :rtype: tuple[int, float] """ if isinstance(what, dns.message.Message): @@ -133,13 +132,14 @@ async def receive_udp( ) -> Any: """Read a DNS message from a UDP socket. - *sock*, a ``dns.asyncbackend.DatagramSocket``. + :param sock: The socket to read from. + :type sock: :py:class:`dns.asyncbackend.DatagramSocket` - See :py:func:`dns.query.receive_udp()` for the documentation of the other - parameters, and exceptions. + See :py:func:`dns.query.receive_udp` for the documentation of the other + parameters and exceptions. - Returns a ``(dns.message.Message, float, tuple)`` tuple of the received message, the - received time, and the address where the message arrived from. + :returns: A ``(message, received_time, from_address)`` tuple. + :rtype: tuple """ wire = b"" @@ -197,13 +197,13 @@ async def udp( ) -> dns.message.Message: """Return the response obtained after sending a query via UDP. - *sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``, - the socket to use for the query. If ``None``, the default, a - socket is created. Note that if a socket is provided, the - *source*, *source_port*, and *backend* are ignored. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. + :param sock: The socket to use. If ``None`` (the default), a socket is + created. Note that if a socket is provided, *source*, *source_port*, + and *backend* are ignored. + :type sock: :py:class:`dns.asyncbackend.DatagramSocket` or ``None`` + :param backend: The async backend. If ``None`` (the default), dnspython + will use the default backend. + :type backend: :py:class:`dns.asyncbackend.Backend` or ``None`` See :py:func:`dns.query.udp()` for the documentation of the other parameters, exceptions, and return type of this method. @@ -264,18 +264,18 @@ async def udp_with_fallback( """Return the response to the query, trying UDP first and falling back to TCP if UDP results in a truncated response. - *udp_sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``, - the socket to use for the UDP query. If ``None``, the default, a - socket is created. Note that if a socket is provided the *source*, - *source_port*, and *backend* are ignored for the UDP query. - - *tcp_sock*, a ``dns.asyncbackend.StreamSocket``, or ``None``, the - socket to use for the TCP query. If ``None``, the default, a - socket is created. Note that if a socket is provided *where*, - *source*, *source_port*, and *backend* are ignored for the TCP query. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. + :param udp_sock: The socket to use for the UDP query. If ``None`` + (the default), a socket is created. Note that if a socket is provided, + *source*, *source_port*, and *backend* are ignored for the UDP query. + :type udp_sock: :py:class:`dns.asyncbackend.DatagramSocket` or ``None`` + :param tcp_sock: The socket to use for the TCP query. If ``None`` + (the default), a socket is created. Note that if a socket is provided, + *where*, *source*, *source_port*, and *backend* are ignored for the + TCP query. + :type tcp_sock: :py:class:`dns.asyncbackend.StreamSocket` or ``None`` + :param backend: The async backend. If ``None`` (the default), dnspython + will use the default backend. + :type backend: :py:class:`dns.asyncbackend.Backend` or ``None`` See :py:func:`dns.query.udp_with_fallback()` for the documentation of the other parameters, exceptions, and return type of this @@ -321,7 +321,8 @@ async def send_tcp( ) -> tuple[int, float]: """Send a DNS message to the specified TCP socket. - *sock*, a ``dns.asyncbackend.StreamSocket``. + :param sock: The socket to use. + :type sock: :py:class:`dns.asyncbackend.StreamSocket` See :py:func:`dns.query.send_tcp()` for the documentation of the other parameters, exceptions, and return type of this method. @@ -364,7 +365,8 @@ async def receive_tcp( ) -> tuple[dns.message.Message, float]: """Read a DNS message from a TCP socket. - *sock*, a ``dns.asyncbackend.StreamSocket``. + :param sock: The socket to use. + :type sock: :py:class:`dns.asyncbackend.StreamSocket` See :py:func:`dns.query.receive_tcp()` for the documentation of the other parameters, exceptions, and return type of this method. @@ -399,13 +401,13 @@ async def tcp( ) -> dns.message.Message: """Return the response obtained after sending a query via TCP. - *sock*, a ``dns.asyncbacket.StreamSocket``, or ``None``, the - socket to use for the query. If ``None``, the default, a socket - is created. Note that if a socket is provided - *where*, *port*, *source*, *source_port*, and *backend* are ignored. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. + :param sock: The socket to use. If ``None`` (the default), a socket is + created. Note that if a socket is provided, *where*, *port*, + *source*, *source_port*, and *backend* are ignored. + :type sock: :py:class:`dns.asyncbackend.StreamSocket` or ``None`` + :param backend: The async backend. If ``None`` (the default), dnspython + will use the default backend. + :type backend: :py:class:`dns.asyncbackend.Backend` or ``None`` See :py:func:`dns.query.tcp()` for the documentation of the other parameters, exceptions, and return type of this method. @@ -463,15 +465,14 @@ async def tls( ) -> dns.message.Message: """Return the response obtained after sending a query via TLS. - *sock*, an ``asyncbackend.StreamSocket``, or ``None``, the socket - to use for the query. If ``None``, the default, a socket is - created. Note that if a socket is provided, it must be a - connected SSL stream socket, and *where*, *port*, - *source*, *source_port*, *backend*, *ssl_context*, and *server_hostname* - are ignored. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. + :param sock: The socket to use. If ``None`` (the default), a socket is + created. Note that if a socket is provided, it must be a connected + SSL stream socket, and *where*, *port*, *source*, *source_port*, + *backend*, *ssl_context*, and *server_hostname* are ignored. + :type sock: :py:class:`dns.asyncbackend.StreamSocket` or ``None`` + :param backend: The async backend. If ``None`` (the default), dnspython + will use the default backend. + :type backend: :py:class:`dns.asyncbackend.Backend` or ``None`` See :py:func:`dns.query.tls()` for the documentation of the other parameters, exceptions, and return type of this method. @@ -550,11 +551,10 @@ async def https( ) -> dns.message.Message: """Return the response obtained after sending a query via DNS-over-HTTPS. - *client*, a ``httpx.AsyncClient``. If provided, the client to use for - the query. - - Unlike the other dnspython async functions, a backend cannot be provided - in this function because httpx always auto-detects the async backend. + :param client: If provided, the client to use for the query. Unlike the + other dnspython async functions, a backend cannot be provided here + because httpx always auto-detects the async backend. + :type client: ``httpx.AsyncClient`` or ``None`` See :py:func:`dns.query.https()` for the documentation of the other parameters, exceptions, and return type of this method. @@ -788,8 +788,9 @@ async def quic( """Return the response obtained after sending an asynchronous query via DNS-over-QUIC. - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. + :param backend: The async backend. If ``None`` (the default), dnspython + will use the default backend. + :type backend: :py:class:`dns.asyncbackend.Backend` or ``None`` See :py:func:`dns.query.quic()` for the documentation of the other parameters, exceptions, and return type of this method. @@ -910,8 +911,9 @@ async def inbound_xfr( """Conduct an inbound transfer and apply it via a transaction from the txn_manager. - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. + :param backend: The async backend. If ``None`` (the default), dnspython + will use the default backend. + :type backend: :py:class:`dns.asyncbackend.Backend` or ``None`` See :py:func:`dns.query.inbound_xfr()` for the documentation of the other parameters, exceptions, and return type of this method. diff --git a/dns/asyncresolver.py b/dns/asyncresolver.py index 752b4c6c..809821dd 100644 --- a/dns/asyncresolver.py +++ b/dns/asyncresolver.py @@ -59,8 +59,9 @@ class Resolver(dns.resolver.BaseResolver): ) -> dns.resolver.Answer: """Query nameservers asynchronously to find the answer to the question. - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. + :param backend: The async backend. If ``None`` (the default), dnspython + will use the default backend. + :type backend: :py:class:`dns.asyncbackend.Backend` or ``None`` See :py:func:`dns.resolver.Resolver.resolve()` for the documentation of the other parameters, exceptions, and return @@ -118,8 +119,8 @@ class Resolver(dns.resolver.BaseResolver): This utilizes the resolve() method to perform a PTR lookup on the specified IP address. - *ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get - the PTR record for. + :param ipaddr: The IPv4 or IPv6 address to look up. + :type ipaddr: str All other arguments that can be passed to the resolve() function except for rdtype and rdclass are also supported by this @@ -148,10 +149,11 @@ class Resolver(dns.resolver.BaseResolver): This utilizes the resolve() method to perform A and/or AAAA lookups on the specified name. - *qname*, a ``dns.name.Name`` or ``str``, the name to resolve. - - *family*, an ``int``, the address family. If socket.AF_UNSPEC - (the default), both A and AAAA records will be retrieved. + :param name: The name to resolve. + :type name: :py:class:`dns.name.Name` or str + :param family: The address family. If ``socket.AF_UNSPEC`` (the + default), both A and AAAA records will be retrieved. + :type family: int All other arguments that can be passed to the resolve() function except for rdtype and rdclass are also supported by this @@ -212,13 +214,13 @@ class Resolver(dns.resolver.BaseResolver): The canonical name is the name the resolver uses for queries after all CNAME and DNAME renamings have been applied. - *name*, a ``dns.name.Name`` or ``str``, the query name. - - This method can raise any exception that ``resolve()`` can - raise, other than ``dns.resolver.NoAnswer`` and - ``dns.resolver.NXDOMAIN``. + :param name: The query name. + :type name: :py:class:`dns.name.Name` or str + :rtype: :py:class:`dns.name.Name` - Returns a ``dns.name.Name``. + This method can raise any exception that + :py:meth:`~dns.asyncresolver.Resolver.resolve` can raise, other than + :py:exc:`dns.resolver.NoAnswer` and :py:exc:`dns.resolver.NXDOMAIN`. """ try: answer = await self.resolve(name, raise_on_no_answer=False) @@ -369,7 +371,7 @@ async def zone_for_name( ) -> dns.name.Name: """Find the name of the zone which contains the specified name. - See :py:func:`dns.resolver.Resolver.zone_for_name` for more + See :py:func:`dns.resolver.zone_for_name` for more information on the parameters and possible exceptions. """ @@ -404,20 +406,18 @@ async def make_resolver_at( ) -> Resolver: """Make a stub resolver using the specified destination as the full resolver. - *where*, a ``dns.name.Name`` or ``str`` the domain name or IP address of the - full resolver. - - *port*, an ``int``, the port to use. If not specified, the default is 53. - - *family*, an ``int``, the address family to use. This parameter is used if - *where* is not an address. The default is ``socket.AF_UNSPEC`` in which case - the first address returned by ``resolve_name()`` will be used, otherwise the - first address of the specified family will be used. - - *resolver*, a ``dns.asyncresolver.Resolver`` or ``None``, the resolver to use for - resolution of hostnames. If not specified, the default resolver will be used. - - Returns a ``dns.resolver.Resolver`` or raises an exception. + :param where: The domain name or IP address of the full resolver. + :type where: :py:class:`dns.name.Name` or str + :param port: The port to use. Default is 53. + :type port: int + :param family: The address family. Used only when *where* is not an + address literal. ``socket.AF_UNSPEC`` (default) uses the first + address returned; otherwise the first address of the given family. + :type family: int + :param resolver: The resolver to use for hostname resolution. If + ``None``, the default resolver is used. + :type resolver: :py:class:`dns.asyncresolver.Resolver` or ``None`` + :rtype: :py:class:`dns.resolver.Resolver` """ if resolver is None: resolver = get_default_resolver() diff --git a/dns/btree.py b/dns/btree.py index 5c1156b0..e9e03b79 100644 --- a/dns/btree.py +++ b/dns/btree.py @@ -79,8 +79,9 @@ class _Node(Generic[KT, ET]): """Get the index of the ``Element`` matching ``key`` or the index of its least successor. - Returns a tuple of the index and an ``equal`` boolean that is ``True`` iff. - the key was found. + :returns: A tuple of the index and an ``equal`` boolean that is ``True`` + iff the key was found. + :rtype: tuple[int, bool] """ l = len(self.elts) if l > 0 and key > self.elts[l - 1].key(): @@ -118,8 +119,8 @@ class _Node(Generic[KT, ET]): """Get the node associated with key and its index, doing copy-on-write if we have to descend. - Returns a tuple of the node and the index, or the tuple ``(None, 0)`` - if the key was not found. + :returns: A tuple of the node and the index, or ``(None, 0)`` + if the key was not found. """ i, equal = self.search_in_node(key) if equal: @@ -198,7 +199,8 @@ class _Node(Generic[KT, ET]): def try_left_steal(self, parent: "_Node[KT, ET]", index: int) -> bool: """Try to steal from this Node's left sibling for balancing purposes. - Returns ``True`` if the theft was successful, or ``False`` if not. + :returns: ``True`` if the theft was successful, ``False`` if not. + :rtype: bool """ if index != 0: left = parent.children[index - 1] @@ -217,7 +219,8 @@ class _Node(Generic[KT, ET]): def try_right_steal(self, parent: "_Node[KT, ET]", index: int) -> bool: """Try to steal from this Node's right sibling for balancing purposes. - Returns ``True`` if the theft was successful, or ``False`` if not. + :returns: ``True`` if the theft was successful, ``False`` if not. + :rtype: bool """ if index + 1 < len(parent.children): right = parent.children[index + 1] @@ -665,11 +668,10 @@ class BTree(Generic[KT, ET]): def insert_element(self, elt: ET, in_order: bool = False) -> ET | None: """Insert the element into the BTree. - If *in_order* is ``True``, then extra work will be done to make left siblings - full, which optimizes storage space when the the elements are inserted in-order - or close to it. - - Returns the previously existing element at the element's key or ``None``. + :param bool in_order: If ``True``, extra work will be done to make left + siblings full, which optimizes storage space when elements are inserted + in-order or close to it. + :returns: The previously existing element at the element's key, or ``None``. """ self._check_mutable_and_park() cloned = self.root.maybe_cow(self.creator) @@ -711,14 +713,14 @@ class BTree(Generic[KT, ET]): def delete_key(self, key: KT) -> ET | None: """Delete the element matching *key* from the BTree. - Returns the matching element or ``None`` if it does not exist. + :returns: The matching element, or ``None`` if it does not exist. """ return self._delete(key, None) def delete_exact(self, element: ET) -> ET | None: """Delete *element* from the BTree. - Returns the matching element or ``None`` if it was not in the BTree. + :returns: The matching element, or ``None`` if it was not in the BTree. """ delt = self._delete(element.key(), element) assert delt is element diff --git a/dns/btreezone.py b/dns/btreezone.py index fdb71695..1d981651 100644 --- a/dns/btreezone.py +++ b/dns/btreezone.py @@ -28,12 +28,38 @@ import dns.zone class NodeFlags(enum.IntFlag): + """Flags that classify a node's role in the zone. + + ``ORIGIN`` is set on the zone origin node. + + ``DELEGATION`` is set at NS delegation points (not at the origin, and not + on nodes beneath a delegation). + + ``GLUE`` is set on nodes that are proper subdomains of a delegation point. + """ + ORIGIN = 0x01 DELEGATION = 0x02 GLUE = 0x04 class Node(dns.node.Node): + """A BTree zone node, extending :py:class:`dns.node.Node` with ``flags`` and + ``id`` fields. + + .. attribute:: flags + + The node's role flags. + + :type: :py:class:`dns.btreezone.NodeFlags` + + .. attribute:: id + + The version id of the last write that touched this node. + + :type: int + """ + __slots__ = ["flags", "id"] def __init__(self, flags: NodeFlags | None = None): @@ -47,20 +73,41 @@ class Node(dns.node.Node): self.id = 0 def is_delegation(self): + """Return ``True`` if this node is an NS delegation point. + + :rtype: bool + """ return (self.flags & NodeFlags.DELEGATION) != 0 def is_glue(self): + """Return ``True`` if this node is beneath a delegation point. + + :rtype: bool + """ return (self.flags & NodeFlags.GLUE) != 0 def is_origin(self): + """Return ``True`` if this node is the zone origin. + + :rtype: bool + """ return (self.flags & NodeFlags.ORIGIN) != 0 def is_origin_or_glue(self): + """Return ``True`` if this node is at the origin or beneath a delegation. + + :rtype: bool + """ return (self.flags & (NodeFlags.ORIGIN | NodeFlags.GLUE)) != 0 @dns.immutable.immutable class ImmutableNode(Node): + """An immutable :py:class:`dns.btreezone.Node`. + + Mutation methods raise :py:exc:`TypeError`. + """ + def __init__(self, node: Node): super().__init__() self.id = node.id @@ -107,13 +154,21 @@ class ImmutableNode(Node): class Delegations(dns.btree.BTreeSet[dns.name.Name]): + """A sorted set of delegation-point names. + + Used by :py:class:`dns.btreezone.WritableVersion` and + :py:class:`dns.btreezone.ImmutableVersion` to efficiently determine + whether a given name is at or beneath a delegation point. + """ + def get_delegation(self, name: dns.name.Name) -> tuple[dns.name.Name | None, bool]: """Get the delegation applicable to *name*, if it exists. - If there delegation, then return a tuple consisting of the name of - the delegation point, and a boolean which is `True` if the name is a proper - subdomain of the delegation point, and `False` if it is equal to the delegation - point. + :returns: A tuple of the delegation point name and a boolean which is + ``True`` if *name* is a proper subdomain of the delegation point, + or ``False`` if it is equal to the delegation point. If there is + no applicable delegation, returns ``(None, False)``. + :rtype: tuple[:py:class:`dns.name.Name` or ``None``, bool] """ cursor = self.cursor() cursor.seek(name, before=False) @@ -139,6 +194,17 @@ class Delegations(dns.btree.BTreeSet[dns.name.Name]): class WritableVersion(dns.zone.WritableVersion): + """A mutable version of a :py:class:`dns.btreezone.Zone`. + + Extends :py:class:`dns.zone.WritableVersion` with a + :py:class:`dns.btreezone.Delegations` index and automatic management of + ``NodeFlags.ORIGIN``, ``NodeFlags.DELEGATION``, and ``NodeFlags.GLUE`` + flags on every node. + + Instances are created internally by the zone; callers should not + construct them directly. + """ + def __init__(self, zone: dns.zone.Zone, replacement: bool = False): super().__init__(zone, True) if not replacement: @@ -171,6 +237,14 @@ class WritableVersion(dns.zone.WritableVersion): return (node, name) def update_glue_flag(self, name: dns.name.Name, is_glue: bool) -> None: + """Set or clear the ``NodeFlags.GLUE`` flag on all nodes that are + subdomains of *name*. + + :param name: The delegation-point name whose subtree should be updated. + :type name: :py:class:`dns.name.Name` + :param is_glue: ``True`` to set the GLUE flag; ``False`` to clear it. + :type is_glue: bool + """ cursor = self.nodes.cursor() # pyright: ignore cursor.seek(name, False) updates = [] @@ -202,6 +276,15 @@ class WritableVersion(dns.zone.WritableVersion): self.nodes[ename] = node def delete_node(self, name: dns.name.Name) -> None: + """Delete the node at *name*, updating delegation tracking as needed. + + If *name* is a delegation point, it is removed from the delegations + index and the GLUE flag is cleared from its subtree. If *name* does + not exist in the zone, this method is a no-op. + + :param name: The name of the node to delete. + :type name: :py:class:`dns.name.Name` + """ name = self._validate_name(name) node = self.nodes.get(name) if node is not None: @@ -214,6 +297,17 @@ class WritableVersion(dns.zone.WritableVersion): def put_rdataset( self, name: dns.name.Name, rdataset: dns.rdataset.Rdataset ) -> None: + """Store *rdataset* at *name*, updating delegation flags as needed. + + If *rdataset* is an NS rdataset and *name* is not the origin or beneath + an existing delegation, the ``DELEGATION`` flag is set on the node and + the ``GLUE`` flag is set on all nodes in *name*'s subtree. + + :param name: The owner name. + :type name: :py:class:`dns.name.Name` + :param rdataset: The rdataset to store. + :type rdataset: :py:class:`dns.rdataset.Rdataset` + """ node, name = self._maybe_cow_with_name(name) if ( rdataset.rdtype == dns.rdatatype.NS @@ -231,6 +325,19 @@ class WritableVersion(dns.zone.WritableVersion): rdtype: dns.rdatatype.RdataType, covers: dns.rdatatype.RdataType, ) -> None: + """Delete the rdataset with *rdtype* and *covers* at *name*. + + If the deleted rdataset was the NS rdataset at a delegation point, + the ``DELEGATION`` flag is cleared from that node and the ``GLUE`` + flag is cleared from all nodes in its subtree. + + :param name: The owner name. + :type name: :py:class:`dns.name.Name` + :param rdtype: The rdata type to remove. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :param covers: The covered type (usually ``dns.rdatatype.NONE``). + :type covers: :py:class:`dns.rdatatype.RdataType` + """ node, name = self._maybe_cow_with_name(name) if rdtype == dns.rdatatype.NS and name in self.delegations: # pyright: ignore node.flags &= ~NodeFlags.DELEGATION # type: ignore @@ -243,6 +350,51 @@ class WritableVersion(dns.zone.WritableVersion): @dataclass(frozen=True) class Bounds: + """The result of a :py:meth:`~dns.btreezone.ImmutableVersion.bounds` query. + + Useful for constructing authoritative responses and for on-the-fly DNSSEC + signatures. + + .. attribute:: name + + The queried name. + + :type: :py:class:`dns.name.Name` + + .. attribute:: left + + The greatest name in the zone that is less than or equal to ``name``. + + :type: :py:class:`dns.name.Name` + + .. attribute:: right + + The least name in the zone that is greater than ``name``, or ``None`` + if ``name`` is greater than every name in the zone. + + :type: :py:class:`dns.name.Name` or ``None`` + + .. attribute:: closest_encloser + + The name with the greatest number of labels that is a common ancestor + of ``name`` and is present in the zone (explicitly or as an implied + empty non-terminal). + + :type: :py:class:`dns.name.Name` + + .. attribute:: is_equal + + ``True`` if ``name`` is present in the zone (i.e. ``name == left``). + + :type: bool + + .. attribute:: is_delegation + + ``True`` if the left bound is a delegation point. + + :type: bool + """ + name: dns.name.Name left: dns.name.Name right: dns.name.Name | None @@ -267,6 +419,16 @@ class Bounds: @dns.immutable.immutable class ImmutableVersion(dns.zone.Version): + """An immutable, committed version of a :py:class:`dns.btreezone.Zone`. + + In addition to the standard read-only zone API, provides the + :py:meth:`bounds` method for DNSSEC and authoritative-response support. + + Instances are created internally when a + :py:class:`dns.btreezone.WritableVersion` is committed; callers should + not construct them directly. + """ + def __init__(self, version: dns.zone.Version): if not isinstance(version, WritableVersion): raise ValueError( @@ -286,12 +448,12 @@ class ImmutableVersion(dns.zone.Version): self.delegations.make_immutable() def bounds(self, name: dns.name.Name | str) -> Bounds: - """Return the 'bounds' of *name* in its zone. + """Return the bounds of *name* in its zone. The bounds information is useful when making an authoritative response, as it can be used to determine whether the query name is at or beneath a delegation - point. The other data in the ``Bounds`` object is useful for making on-the-fly - DNSSEC signatures. + point. The other data in the :py:class:`dns.btreezone.Bounds` object is useful + for making on-the-fly DNSSEC signatures. The left bound of *name* is *name* itself if it is in the zone, or the greatest predecessor which is in the zone. @@ -304,11 +466,15 @@ class ImmutableVersion(dns.zone.Version): *name* that is in the zone, either explicitly or by the implied existence of empty non-terminals. - The bounds *is_equal* field is ``True`` if and only if *name* is equal to - its left bound. + The *is_equal* field of the result is ``True`` if and only if *name* is equal + to its left bound. + + The *is_delegation* field of the result is ``True`` if and only if the left + bound is a delegation point. - The bounds *is_delegation* field is ``True`` if and only if the left bound is a - delegation point. + :param name: The name to look up. + :type name: :py:class:`dns.name.Name` or str + :rtype: :py:class:`dns.btreezone.Bounds` """ assert self.origin is not None # validate the origin because we may need to relativize @@ -355,6 +521,22 @@ class ImmutableVersion(dns.zone.Version): class Zone(dns.versioned.Zone): + """A versioned DNS zone backed by a BTree. + + Extends :py:class:`dns.versioned.Zone` with: + + - **Sorted iteration order**: names are always visited in DNS canonical order. + - **Automatic flag tracking**: every node is tagged with + :py:class:`dns.btreezone.NodeFlags` (``ORIGIN``, ``DELEGATION``, + ``GLUE``) as rdatasets are added and removed. + - **Efficient copy-on-write versioning**: the underlying + :py:class:`dns.btree.BTreeDict` shares structure between versions so + that creating a new version is cheap. + - **DNSSEC / authoritative-response support**: committed versions expose + :py:meth:`~dns.btreezone.ImmutableVersion.bounds`, which returns the + nearest names and closest encloser for any query name. + """ + node_factory: Callable[[], dns.node.Node] = Node map_factory: Callable[[], MutableMapping[dns.name.Name, dns.node.Node]] = cast( Callable[[], MutableMapping[dns.name.Name, dns.node.Node]], diff --git a/dns/dnssec.py b/dns/dnssec.py index 6675eaa5..35427b58 100644 --- a/dns/dnssec.py +++ b/dns/dnssec.py @@ -73,9 +73,9 @@ RRsetSigner = Callable[[dns.transaction.Transaction, dns.rrset.RRset], None] def algorithm_from_text(text: str) -> Algorithm: """Convert text into a DNSSEC algorithm value. - *text*, a ``str``, the text to convert to into an algorithm value. - - Returns an ``int``. + :param text: The text to convert into an algorithm value. + :type text: str + :rtype: int """ return Algorithm.from_text(text) @@ -84,9 +84,9 @@ def algorithm_from_text(text: str) -> Algorithm: def algorithm_to_text(value: Algorithm | int) -> str: """Convert a DNSSEC algorithm value to text - *value*, a ``dns.dnssec.Algorithm``. - - Returns a ``str``, the name of a DNSSEC algorithm. + :param value: The algorithm value. + :type value: :py:class:`dns.dnssectypes.Algorithm` + :rtype: str """ return Algorithm.to_text(value) @@ -109,9 +109,9 @@ def to_timestamp(value: datetime | str | float | int) -> int: def key_id(key: DNSKEY | CDNSKEY) -> int: """Return the key id (a 16-bit number) for the specified key. - *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` - - Returns an ``int`` between 0 and 65535 + :param key: The DNSKEY or CDNSKEY rdata. + :type key: :py:class:`dns.rdtypes.ANY.DNSKEY.DNSKEY` + :rtype: int """ return key.key_id() @@ -178,31 +178,27 @@ def make_ds( ) -> DS: """Create a DS record for a DNSSEC key. - *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record. - - *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` or ``dns.rdtypes.ANY.DNSKEY.CDNSKEY``, - the key the DS is about. - - *algorithm*, a ``str`` or ``int`` specifying the hash algorithm. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. - - *origin*, a ``dns.name.Name`` or ``None``. If *key* is a relative name, - then it will be made absolute using the specified origin. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - *validating*, a ``bool``. If ``True``, then policy is checked in - validating mode, i.e. "Is it ok to validate using this digest algorithm?". - Otherwise the policy is checked in creating mode, i.e. "Is it ok to create a DS with - this digest algorithm?". - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Raises ``DeniedByPolicy`` if the algorithm is denied by policy. - - Returns a ``dns.rdtypes.ANY.DS.DS`` + :param name: The owner name of the DS record. + :type name: :py:class:`dns.name.Name` or str + :param key: The key the DS is about. + :type key: :py:class:`dns.rdtypes.ANY.DNSKEY.DNSKEY` or + :py:class:`dns.rdtypes.ANY.CDNSKEY.CDNSKEY` + :param algorithm: The hash algorithm. Currently supported: ``"SHA1"``, + ``"SHA256"``, ``"SHA384"`` (case-insensitive). + :type algorithm: str or int + :param origin: If *key* is a relative name, it will be made absolute + using this origin. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param policy: The policy to use. If ``None``, ``dns.dnssec.default_policy`` + is used (defaults to RFC 8624 policy). + :type policy: :py:class:`dns.dnssec.Policy` or ``None`` + :param validating: If ``True``, policy is checked in validating mode ("Is it + ok to validate using this digest algorithm?"). Otherwise checked in + creating mode. + :type validating: bool + :raises UnsupportedAlgorithm: If the algorithm is unknown. + :raises DeniedByPolicy: If the algorithm is denied by policy. + :rtype: :py:class:`dns.rdtypes.ANY.DS.DS` """ if policy is None: @@ -253,21 +249,19 @@ def make_cds( ) -> CDS: """Create a CDS record for a DNSSEC key. - *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record. - - *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` or ``dns.rdtypes.ANY.DNSKEY.CDNSKEY``, - the key the DS is about. - - *algorithm*, a ``str`` or ``int`` specifying the hash algorithm. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. - - *origin*, a ``dns.name.Name`` or ``None``. If *key* is a relative name, - then it will be made absolute using the specified origin. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Returns a ``dns.rdtypes.ANY.DS.CDS`` + :param name: The owner name of the DS record. + :type name: :py:class:`dns.name.Name` or str + :param key: The key the DS is about. + :type key: :py:class:`dns.rdtypes.ANY.DNSKEY.DNSKEY` or + :py:class:`dns.rdtypes.ANY.CDNSKEY.CDNSKEY` + :param algorithm: The hash algorithm. Currently supported: ``"SHA1"``, + ``"SHA256"``, ``"SHA384"`` (case-insensitive). + :type algorithm: str or int + :param origin: If *key* is a relative name, it will be made absolute + using this origin. + :type origin: :py:class:`dns.name.Name` or ``None`` + :raises UnsupportedAlgorithm: If the algorithm is unknown. + :rtype: :py:class:`dns.rdtypes.ANY.CDS.CDS` """ ds = make_ds(name, key, algorithm, origin) @@ -335,29 +329,22 @@ def _validate_rrsig( ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) tuple. - *rrsig*, a ``dns.rdata.Rdata``, the signature to validate. - - *keys*, the key dictionary, used to find the DNSKEY associated - with a given name. The dictionary is keyed by a - ``dns.name.Name``, and has ``dns.node.Node`` or - ``dns.rdataset.Rdataset`` values. - - *origin*, a ``dns.name.Name`` or ``None``, the origin to use for relative - names. - - *now*, a ``float`` or ``None``, the time, in seconds since the epoch, to - use as the current time when validating. If ``None``, the actual current - time is used. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - Raises ``ValidationFailure`` if the signature is expired, not yet valid, - the public key is invalid, the algorithm is unknown, the verification - fails, etc. - - Raises ``UnsupportedAlgorithm`` if the algorithm is recognized by - dnspython but not implemented. + :param rrsig: The signature to validate. + :type rrsig: :py:class:`dns.rdata.Rdata` + :param keys: The key dictionary, keyed by :py:class:`dns.name.Name`, with + :py:class:`dns.node.Node` or :py:class:`dns.rdataset.Rdataset` values. + :param origin: The origin to use for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param now: The current time in seconds since the epoch. If ``None``, + the actual current time is used. + :type now: float or ``None`` + :param policy: The policy to use. If ``None``, ``dns.dnssec.default_policy`` + is used (defaults to RFC 8624 policy). + :type policy: :py:class:`dns.dnssec.Policy` or ``None`` + :raises ValidationFailure: If the signature is expired, not yet valid, the + public key is invalid, the algorithm is unknown, verification fails, etc. + :raises UnsupportedAlgorithm: If the algorithm is recognized but not + implemented. """ if policy is None: @@ -401,32 +388,22 @@ def _validate( """Validate an RRset against a signature RRset, throwing an exception if none of the signatures validate. - *rrset*, the RRset to validate. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *rrsigset*, the signature RRset. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *keys*, the key dictionary, used to find the DNSKEY associated - with a given name. The dictionary is keyed by a - ``dns.name.Name``, and has ``dns.node.Node`` or - ``dns.rdataset.Rdataset`` values. - - *origin*, a ``dns.name.Name``, the origin to use for relative names; - defaults to None. - - *now*, an ``int`` or ``None``, the time, in seconds since the epoch, to - use as the current time when validating. If ``None``, the actual current - time is used. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - Raises ``ValidationFailure`` if the signature is expired, not yet valid, - the public key is invalid, the algorithm is unknown, the verification - fails, etc. + :param rrset: The RRset to validate — a :py:class:`dns.rrset.RRset` or a + (:py:class:`dns.name.Name`, :py:class:`dns.rdataset.Rdataset`) tuple. + :param rrsigset: The signature RRset — a :py:class:`dns.rrset.RRset` or a + (:py:class:`dns.name.Name`, :py:class:`dns.rdataset.Rdataset`) tuple. + :param keys: The key dictionary, keyed by :py:class:`dns.name.Name`, with + :py:class:`dns.node.Node` or :py:class:`dns.rdataset.Rdataset` values. + :param origin: The origin to use for relative names. Defaults to ``None``. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param now: The current time in seconds since the epoch. If ``None``, + the actual current time is used. + :type now: int or ``None`` + :param policy: The policy to use. If ``None``, ``dns.dnssec.default_policy`` + is used (defaults to RFC 8624 policy). + :type policy: :py:class:`dns.dnssec.Policy` or ``None`` + :raises ValidationFailure: If the signature is expired, not yet valid, the + public key is invalid, the algorithm is unknown, verification fails, etc. """ if policy is None: @@ -478,47 +455,37 @@ def _sign( ) -> RRSIG: """Sign RRset using private key. - *rrset*, the RRset to validate. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *private_key*, the private key to use for signing, a - ``cryptography.hazmat.primitives.asymmetric`` private key class applicable - for DNSSEC. - - *signer*, a ``dns.name.Name``, the Signer's name. - - *dnskey*, a ``DNSKEY`` matching ``private_key``. - - *inception*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the - signature inception time. If ``None``, the current time is used. If a ``str``, the - format is "YYYYMMDDHHMMSS" or alternatively the number of seconds since the UNIX - epoch in text form; this is the same the RRSIG rdata's text form. - Values of type `int` or `float` are interpreted as seconds since the UNIX epoch. - - *expiration*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature - expiration time. If ``None``, the expiration time will be the inception time plus - the value of the *lifetime* parameter. See the description of *inception* above - for how the various parameter types are interpreted. - - *lifetime*, an ``int`` or ``None``, the signature lifetime in seconds. This - parameter is only meaningful if *expiration* is ``None``. - - *verify*, a ``bool``. If set to ``True``, the signer will verify signatures - after they are created; the default is ``False``. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - *origin*, a ``dns.name.Name`` or ``None``. If ``None``, the default, then all - names in the rrset (including its owner name) must be absolute; otherwise the - specified origin will be used to make names absolute when signing. - - *deterministic*, a ``bool``. If ``True``, the default, use deterministic - (reproducible) signatures when supported by the algorithm used for signing. - Currently, this only affects ECDSA. - - Raises ``DeniedByPolicy`` if the signature is denied by policy. + :param rrset: The RRset to sign — a :py:class:`dns.rrset.RRset` or a + (:py:class:`dns.name.Name`, :py:class:`dns.rdataset.Rdataset`) tuple. + :param private_key: The private key to use for signing. + :param signer: The signer's name. + :type signer: :py:class:`dns.name.Name` + :param dnskey: A DNSKEY matching *private_key*. + :param inception: The signature inception time. If ``None``, the current + time is used. If a ``str``, the format is ``"YYYYMMDDHHMMSS"`` or the + number of seconds since the UNIX epoch. ``int`` and ``float`` values + are interpreted as seconds since the UNIX epoch. + :type inception: datetime, str, int, float, or ``None`` + :param expiration: The signature expiration time. If ``None``, the + expiration is *inception* plus *lifetime*. Interpreted the same as + *inception*. + :type expiration: datetime, str, int, float, or ``None`` + :param lifetime: The signature lifetime in seconds. Only meaningful if + *expiration* is ``None``. + :type lifetime: int or ``None`` + :param verify: If ``True``, signatures will be verified after creation. + Default is ``False``. + :type verify: bool + :param policy: The policy to use. If ``None``, ``dns.dnssec.default_policy`` + is used (defaults to RFC 8624 policy). + :type policy: :py:class:`dns.dnssec.Policy` or ``None`` + :param origin: If ``None`` (the default), all names must be absolute. + Otherwise, this origin is used to make names absolute when signing. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param deterministic: If ``True`` (the default), use deterministic + (reproducible) signatures when supported. Currently affects ECDSA. + :type deterministic: bool + :raises DeniedByPolicy: If the signature is denied by policy. """ if policy is None: @@ -597,18 +564,16 @@ def _make_rrsig_signature_data( ) -> bytes: """Create signature rdata. - *rrset*, the RRset to sign/validate. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *rrsig*, a ``dns.rdata.Rdata``, the signature to validate, or the - signature template used when signing. - - *origin*, a ``dns.name.Name`` or ``None``, the origin to use for relative - names. - - Raises ``UnsupportedAlgorithm`` if the algorithm is recognized by - dnspython but not implemented. + :param rrset: The RRset to sign/validate — a :py:class:`dns.rrset.RRset` + or a (:py:class:`dns.name.Name`, :py:class:`dns.rdataset.Rdataset`) + tuple. + :param rrsig: The signature to validate, or the signature template used + when signing. + :type rrsig: :py:class:`dns.rdata.Rdata` + :param origin: The origin to use for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :raises UnsupportedAlgorithm: If the algorithm is recognized but not + implemented. """ if isinstance(origin, str): @@ -665,21 +630,19 @@ def _make_dnskey( ) -> DNSKEY: """Convert a public key to DNSKEY Rdata - *public_key*, a ``PublicKey`` (``GenericPublicKey`` or - ``cryptography.hazmat.primitives.asymmetric``) to convert. - - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - *flags*: DNSKEY flags field as an integer. - - *protocol*: DNSKEY protocol field as an integer. - - Raises ``ValueError`` if the specified key algorithm parameters are not - unsupported, ``TypeError`` if the key type is unsupported, - `UnsupportedAlgorithm` if the algorithm is unknown and - `AlgorithmKeyMismatch` if the algorithm does not match the key type. - - Return DNSKEY ``Rdata``. + :param public_key: The public key to convert (a ``GenericPublicKey`` or + ``cryptography.hazmat.primitives.asymmetric`` key). + :param algorithm: The DNSKEY algorithm. + :type algorithm: str or int + :param flags: DNSKEY flags field. + :type flags: int + :param protocol: DNSKEY protocol field. + :type protocol: int + :raises ValueError: If the key algorithm parameters are unsupported. + :raises TypeError: If the key type is unsupported. + :raises UnsupportedAlgorithm: If the algorithm is unknown. + :raises AlgorithmKeyMismatch: If the algorithm does not match the key type. + :rtype: :py:class:`dns.rdtypes.ANY.DNSKEY.DNSKEY` """ algorithm = Algorithm.make(algorithm) @@ -700,22 +663,19 @@ def _make_cdnskey( ) -> CDNSKEY: """Convert a public key to CDNSKEY Rdata - *public_key*, the public key to convert, a - ``cryptography.hazmat.primitives.asymmetric`` public key class applicable - for DNSSEC. - - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - *flags*: DNSKEY flags field as an integer. - - *protocol*: DNSKEY protocol field as an integer. - - Raises ``ValueError`` if the specified key algorithm parameters are not - unsupported, ``TypeError`` if the key type is unsupported, - `UnsupportedAlgorithm` if the algorithm is unknown and - `AlgorithmKeyMismatch` if the algorithm does not match the key type. - - Return CDNSKEY ``Rdata``. + :param public_key: The public key to convert + (``cryptography.hazmat.primitives.asymmetric`` key for DNSSEC). + :param algorithm: The DNSKEY algorithm. + :type algorithm: str or int + :param flags: DNSKEY flags field. + :type flags: int + :param protocol: DNSKEY protocol field. + :type protocol: int + :raises ValueError: If the key algorithm parameters are unsupported. + :raises TypeError: If the key type is unsupported. + :raises UnsupportedAlgorithm: If the algorithm is unknown. + :raises AlgorithmKeyMismatch: If the algorithm does not match the key type. + :rtype: :py:class:`dns.rdtypes.ANY.CDNSKEY.CDNSKEY` """ dnskey = _make_dnskey(public_key, algorithm, flags, protocol) @@ -740,17 +700,15 @@ def nsec3_hash( Calculate the NSEC3 hash, according to https://tools.ietf.org/html/rfc5155#section-5 - *domain*, a ``dns.name.Name`` or ``str``, the name to hash. - - *salt*, a ``str``, ``bytes``, or ``None``, the hash salt. If a - string, it is decoded as a hex string. - - *iterations*, an ``int``, the number of iterations. - - *algorithm*, a ``str`` or ``int``, the hash algorithm. - The only defined algorithm is SHA1. - - Returns a ``str``, the encoded NSEC3 hash. + :param domain: The name to hash. + :type domain: :py:class:`dns.name.Name` or str + :param salt: The hash salt. If a string, it is decoded as a hex string. + :type salt: str, bytes, or ``None`` + :param iterations: The number of iterations. + :type iterations: int + :param algorithm: The hash algorithm. The only defined algorithm is SHA1. + :type algorithm: str or int + :rtype: str """ b32_conversion = str.maketrans( @@ -798,22 +756,19 @@ def make_ds_rdataset( ) -> dns.rdataset.Rdataset: """Create a DS record from DNSKEY/CDNSKEY/CDS. - *rrset*, the RRset to create DS Rdataset for. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *algorithms*, a set of ``str`` or ``int`` specifying the hash algorithms. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. If the RRset is a CDS, only digest - algorithms matching algorithms are accepted. - - *origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name, - then it will be made absolute using the specified origin. - - Raises ``UnsupportedAlgorithm`` if any of the algorithms are unknown and - ``ValueError`` if the given RRset is not usable. - - Returns a ``dns.rdataset.Rdataset`` + :param rrset: The RRset — a :py:class:`dns.rrset.RRset` or a + (:py:class:`dns.name.Name`, :py:class:`dns.rdataset.Rdataset`) tuple. + :param algorithms: A set of hash algorithms. Currently supported: + ``"SHA1"``, ``"SHA256"``, ``"SHA384"`` (case-insensitive). If the + RRset is a CDS, only digest algorithms matching *algorithms* are + accepted. + :type algorithms: set of str or int + :param origin: If the key name is relative, it will be made absolute + using this origin. + :type origin: :py:class:`dns.name.Name` or ``None`` + :raises UnsupportedAlgorithm: If any algorithm is unknown. + :raises ValueError: If the given RRset is not usable. + :rtype: :py:class:`dns.rdataset.Rdataset` """ rrname, rdataset = _get_rrname_rdataset(rrset) @@ -854,11 +809,10 @@ def cds_rdataset_to_ds_rdataset( ) -> dns.rdataset.Rdataset: """Create a CDS record from DS. - *rdataset*, a ``dns.rdataset.Rdataset``, to create DS Rdataset for. - - Raises ``ValueError`` if the rdataset is not CDS. - - Returns a ``dns.rdataset.Rdataset`` + :param rdataset: The CDS rdataset to convert to DS. + :type rdataset: :py:class:`dns.rdataset.Rdataset` + :raises ValueError: If the rdataset is not CDS. + :rtype: :py:class:`dns.rdataset.Rdataset` """ if rdataset.rdtype != dns.rdatatype.CDS: @@ -886,21 +840,19 @@ def dnskey_rdataset_to_cds_rdataset( ) -> dns.rdataset.Rdataset: """Create a CDS record from DNSKEY/CDNSKEY. - *name*, a ``dns.name.Name`` or ``str``, the owner name of the CDS record. - - *rdataset*, a ``dns.rdataset.Rdataset``, to create DS Rdataset for. - - *algorithm*, a ``str`` or ``int`` specifying the hash algorithm. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. - - *origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name, - then it will be made absolute using the specified origin. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown or - ``ValueError`` if the rdataset is not DNSKEY/CDNSKEY. - - Returns a ``dns.rdataset.Rdataset`` + :param name: The owner name of the CDS record. + :type name: :py:class:`dns.name.Name` or str + :param rdataset: The DNSKEY/CDNSKEY rdataset to create CDS for. + :type rdataset: :py:class:`dns.rdataset.Rdataset` + :param algorithm: The hash algorithm. Currently supported: ``"SHA1"``, + ``"SHA256"``, ``"SHA384"`` (case-insensitive). + :type algorithm: str or int + :param origin: If the key name is relative, it will be made absolute + using this origin. + :type origin: :py:class:`dns.name.Name` or ``None`` + :raises UnsupportedAlgorithm: If the algorithm is unknown. + :raises ValueError: If the rdataset is not DNSKEY/CDNSKEY. + :rtype: :py:class:`dns.rdataset.Rdataset` """ if rdataset.rdtype not in (dns.rdatatype.DNSKEY, dns.rdatatype.CDNSKEY): @@ -916,9 +868,9 @@ def dnskey_rdataset_to_cdnskey_rdataset( ) -> dns.rdataset.Rdataset: """Create a CDNSKEY record from DNSKEY. - *rdataset*, a ``dns.rdataset.Rdataset``, to create CDNSKEY Rdataset for. - - Returns a ``dns.rdataset.Rdataset`` + :param rdataset: The DNSKEY rdataset to convert to CDNSKEY. + :type rdataset: :py:class:`dns.rdataset.Rdataset` + :rtype: :py:class:`dns.rdataset.Rdataset` """ if rdataset.rdtype != dns.rdatatype.DNSKEY: @@ -996,47 +948,38 @@ def sign_zone( ) -> None: """Sign zone. - *zone*, a ``dns.zone.Zone``, the zone to sign. - - *txn*, a ``dns.transaction.Transaction``, an optional transaction to use for - signing. - - *keys*, a list of (``PrivateKey``, ``DNSKEY``) tuples, to use for signing. KSK/ZSK - roles are assigned automatically if the SEP flag is used, otherwise all RRsets are - signed by all keys. - - *add_dnskey*, a ``bool``. If ``True``, the default, all specified DNSKEYs are - automatically added to the zone on signing. - - *dnskey_ttl*, a``int``, specifies the TTL for DNSKEY RRs. If not specified the TTL - of the existing DNSKEY RRset used or the TTL of the SOA RRset. - - *inception*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature - inception time. If ``None``, the current time is used. If a ``str``, the format is - "YYYYMMDDHHMMSS" or alternatively the number of seconds since the UNIX epoch in text - form; this is the same the RRSIG rdata's text form. Values of type `int` or `float` - are interpreted as seconds since the UNIX epoch. - - *expiration*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature - expiration time. If ``None``, the expiration time will be the inception time plus - the value of the *lifetime* parameter. See the description of *inception* above for - how the various parameter types are interpreted. - - *lifetime*, an ``int`` or ``None``, the signature lifetime in seconds. This - parameter is only meaningful if *expiration* is ``None``. - - *nsec3*, a ``NSEC3PARAM`` Rdata, configures signing using NSEC3. Not yet - implemented. - - *rrset_signer*, a ``Callable``, an optional function for signing RRsets. The - function requires two arguments: transaction and RRset. If the not specified, - ``dns.dnssec.default_rrset_signer`` will be used. - - *deterministic*, a ``bool``. If ``True``, the default, use deterministic - (reproducible) signatures when supported by the algorithm used for signing. - Currently, this only affects ECDSA. - - Returns ``None``. + :param zone: The zone to sign. + :type zone: :py:class:`dns.zone.Zone` + :param txn: An optional transaction to use for signing. + :type txn: :py:class:`dns.transaction.Transaction` or ``None`` + :param keys: A list of (``PrivateKey``, ``DNSKEY``) tuples to use for + signing. KSK/ZSK roles are assigned automatically if the SEP flag is + used; otherwise all RRsets are signed by all keys. + :param add_dnskey: If ``True`` (the default), all specified DNSKEYs are + automatically added to the zone on signing. + :type add_dnskey: bool + :param dnskey_ttl: The TTL for DNSKEY RRs. If not specified, uses the TTL + of the existing DNSKEY RRset or the SOA RRset. + :type dnskey_ttl: int or ``None`` + :param inception: The signature inception time. If ``None``, the current + time is used. If a ``str``, the format is ``"YYYYMMDDHHMMSS"`` or + seconds since UNIX epoch. ``int`` and ``float`` are seconds since epoch. + :type inception: datetime, str, int, float, or ``None`` + :param expiration: The signature expiration time. If ``None``, the + expiration is *inception* plus *lifetime*. Interpreted the same as + *inception*. + :type expiration: datetime, str, int, float, or ``None`` + :param lifetime: The signature lifetime in seconds. Only meaningful if + *expiration* is ``None``. + :type lifetime: int or ``None`` + :param nsec3: If specified, configures signing using NSEC3. Not yet + implemented. + :param rrset_signer: An optional function for signing RRsets, accepting + two arguments: transaction and RRset. If not specified, + ``dns.dnssec.default_rrset_signer`` is used. + :param deterministic: If ``True`` (the default), use deterministic + (reproducible) signatures when supported. Currently affects ECDSA. + :type deterministic: bool """ ksks = [] diff --git a/dns/dnssecalgs/__init__.py b/dns/dnssecalgs/__init__.py index 00db4b16..7f4e0879 100644 --- a/dns/dnssecalgs/__init__.py +++ b/dns/dnssecalgs/__init__.py @@ -50,11 +50,10 @@ def get_algorithm_cls( ) -> type[GenericPrivateKey]: """Get Private Key class from Algorithm. - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Returns a ``dns.dnssecalgs.GenericPrivateKey`` + :param algorithm: The DNSKEY algorithm. + :type algorithm: str or int + :raises UnsupportedAlgorithm: If the algorithm is unknown. + :rtype: type[:py:class:`dns.dnssecalgs.base.GenericPrivateKey`] """ algorithm = Algorithm.make(algorithm) cls = algorithms.get((algorithm, prefix)) @@ -68,11 +67,10 @@ def get_algorithm_cls( def get_algorithm_cls_from_dnskey(dnskey: DNSKEY) -> type[GenericPrivateKey]: """Get Private Key class from DNSKEY. - *dnskey*, a ``DNSKEY`` to get Algorithm class for. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Returns a ``dns.dnssecalgs.GenericPrivateKey`` + :param dnskey: The DNSKEY rdata to get the algorithm class for. + :type dnskey: :py:class:`dns.rdtypes.ANY.DNSKEY.DNSKEY` + :raises UnsupportedAlgorithm: If the algorithm is unknown. + :rtype: type[:py:class:`dns.dnssecalgs.base.GenericPrivateKey`] """ prefix: AlgorithmPrefix = None if dnskey.algorithm == Algorithm.PRIVATEDNS: @@ -91,15 +89,15 @@ def register_algorithm_cls( ) -> None: """Register Algorithm Private Key class. - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - *algorithm_cls*: A `GenericPrivateKey` class. - - *name*, an optional ``dns.name.Name`` or ``str``, for for PRIVATEDNS algorithms. - - *oid*: an optional BER-encoded `bytes` for PRIVATEOID algorithms. - - Raises ``ValueError`` if a name or oid is specified incorrectly. + :param algorithm: The DNSKEY algorithm. + :type algorithm: str or int + :param algorithm_cls: A :py:class:`dns.dnssecalgs.base.GenericPrivateKey` + subclass. + :param name: For PRIVATEDNS algorithms, the algorithm name. + :type name: :py:class:`dns.name.Name`, str, or ``None`` + :param oid: For PRIVATEOID algorithms, a BER-encoded OID. + :type oid: bytes or ``None`` + :raises ValueError: If a name or oid is specified incorrectly. """ if not issubclass(algorithm_cls, GenericPrivateKey): raise TypeError("Invalid algorithm class") diff --git a/dns/e164.py b/dns/e164.py index 5b06e6c0..c0ac3e1c 100644 --- a/dns/e164.py +++ b/dns/e164.py @@ -36,12 +36,12 @@ def from_e164( Non-digits in the text are ignored, i.e. "16505551212", "+1.650.555.1212" and "1 (650) 555-1212" are all the same. - *text*, a ``str``, is an E.164 number in textual form. - - *origin*, a ``dns.name.Name``, the domain in which the number - should be constructed. The default is ``e164.arpa.``. - - Returns a ``dns.name.Name``. + :param text: An E.164 number in textual form. + :type text: str + :param origin: The domain in which the number should be constructed. + Default is ``e164.arpa.`` + :type origin: :py:class:`dns.name.Name` + :rtype: :py:class:`dns.name.Name` """ parts = [d for d in text if d.isdigit()] @@ -61,17 +61,16 @@ def to_e164( emitted as a simple string of digits, prefixed by a '+' (unless *want_plus_prefix* is ``False``). - *name* is a ``dns.name.Name``, the ENUM domain name. - - *origin* is a ``dns.name.Name``, a domain containing the ENUM - domain name. The name is relativized to this domain before being - converted to text. If ``None``, no relativization is done. - - *want_plus_prefix* is a ``bool``. If True, add a '+' to the beginning of - the returned number. - - Returns a ``str``. - + :param name: The ENUM domain name. + :type name: :py:class:`dns.name.Name` + :param origin: A domain containing the ENUM domain name. The name is + relativized to this domain before conversion. If ``None``, no + relativization is done. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param want_plus_prefix: If ``True``, add a ``'+'`` prefix to the + returned number. + :type want_plus_prefix: bool + :rtype: str """ if origin is not None: name = name.relativize(origin) @@ -94,12 +93,12 @@ def query( e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.']) - *number*, a ``str`` is the number to look for. - - *domains* is an iterable containing ``dns.name.Name`` values. - - *resolver*, a ``dns.resolver.Resolver``, is the resolver to use. If - ``None``, the default resolver is used. + :param number: The E.164 number to look up. + :type number: str + :param domains: An iterable of domain names to search. + :param resolver: The resolver to use. If ``None``, the default resolver + is used. + :type resolver: :py:class:`dns.resolver.Resolver` or ``None`` """ if resolver is None: diff --git a/dns/edns.py b/dns/edns.py index 1e38e14d..5366937c 100644 --- a/dns/edns.py +++ b/dns/edns.py @@ -71,15 +71,15 @@ class Option: def __init__(self, otype: OptionType | str): """Initialize an option. - *otype*, a ``dns.edns.OptionType``, is the option type. + :param otype: The option type. + :type otype: :py:class:`dns.edns.OptionType` """ self.otype = OptionType.make(otype) def to_wire(self, file: Any | None = None) -> bytes | None: """Convert an option to wire format. - Returns a ``bytes`` or ``None``. - + :rtype: bytes or ``None`` """ raise NotImplementedError # pragma: no cover @@ -87,9 +87,9 @@ class Option: raise NotImplementedError # pragma: no cover def to_generic(self) -> "GenericOption": - """Creates a dns.edns.GenericOption equivalent of this rdata. + """Create a :py:class:`dns.edns.GenericOption` equivalent of this option. - Returns a ``dns.edns.GenericOption``. + :rtype: :py:class:`dns.edns.GenericOption` """ wire = self.to_wire() assert wire is not None # for mypy @@ -99,12 +99,11 @@ class Option: def from_wire_parser(cls, otype: OptionType, parser: "dns.wire.Parser") -> "Option": """Build an EDNS option object from wire format. - *otype*, a ``dns.edns.OptionType``, is the option type. - - *parser*, a ``dns.wire.Parser``, the parser, which should be - restructed to the option length. - - Returns a ``dns.edns.Option``. + :param otype: The option type. + :type otype: :py:class:`dns.edns.OptionType` + :param parser: The parser, restricted to the option length. + :type parser: :py:class:`dns.wire.Parser` + :rtype: :py:class:`dns.edns.Option` """ raise NotImplementedError # pragma: no cover @@ -194,14 +193,17 @@ class ECSOption(Option): # lgtm[py/missing-equals] """EDNS Client Subnet (ECS, RFC7871)""" def __init__(self, address: str, srclen: int | None = None, scopelen: int = 0): - """*address*, a ``str``, is the client address information. - - *srclen*, an ``int``, the source prefix length, which is the - leftmost number of bits of the address to be used for the - lookup. The default is 24 for IPv4 and 56 for IPv6. - - *scopelen*, an ``int``, the scope prefix length. This value - must be 0 in queries, and should be set in responses. + """Initialize an ECSOption. + + :param address: The client address information. + :type address: str + :param srclen: The source prefix length (leftmost number of bits of the + address to be used for the lookup). Defaults to 24 for IPv4 and 56 + for IPv6. + :type srclen: int or ``None`` + :param scopelen: The scope prefix length. Must be 0 in queries; should + be set in responses. + :type scopelen: int """ super().__init__(OptionType.ECS) @@ -367,11 +369,12 @@ class EDEOption(Option): # lgtm[py/missing-equals] _preserve_case = {"DNSKEY", "DS", "DNSSEC", "RRSIGs", "NSEC", "NXDOMAIN"} def __init__(self, code: EDECode | str, text: str | None = None): - """*code*, a ``dns.edns.EDECode`` or ``str``, the info code of the - extended error. + """Initialize an EDEOption. - *text*, a ``str`` or ``None``, specifying additional information about - the error. + :param code: The info code of the extended error. + :type code: :py:class:`dns.edns.EDECode` or str + :param text: Additional information about the error. + :type text: str or ``None`` """ super().__init__(OptionType.EDE) @@ -529,12 +532,11 @@ def option_from_wire_parser( ) -> Option: """Build an EDNS option object from wire format. - *otype*, an ``int``, is the option type. - - *parser*, a ``dns.wire.Parser``, the parser, which should be - restricted to the option length. - - Returns an instance of a subclass of ``dns.edns.Option``. + :param otype: The option type. + :type otype: int or :py:class:`dns.edns.OptionType` + :param parser: The parser, restricted to the option length. + :type parser: :py:class:`dns.wire.Parser` + :rtype: :py:class:`dns.edns.Option` """ otype = OptionType.make(otype) cls = get_option_class(otype) @@ -546,16 +548,15 @@ def option_from_wire( ) -> Option: """Build an EDNS option object from wire format. - *otype*, an ``int``, is the option type. - - *wire*, a ``bytes``, is the wire-format message. - - *current*, an ``int``, is the offset in *wire* of the beginning - of the rdata. - - *olen*, an ``int``, is the length of the wire-format option data - - Returns an instance of a subclass of ``dns.edns.Option``. + :param otype: The option type. + :type otype: int or :py:class:`dns.edns.OptionType` + :param wire: The wire-format message. + :type wire: bytes + :param current: The offset in *wire* of the beginning of the rdata. + :type current: int + :param olen: The length of the wire-format option data. + :type olen: int + :rtype: :py:class:`dns.edns.Option` """ parser = dns.wire.Parser(wire, current) with parser.restrict_to(olen): @@ -565,9 +566,9 @@ def option_from_wire( def register_type(implementation: Any, otype: OptionType) -> None: """Register the implementation of an option type. - *implementation*, a ``class``, is a subclass of ``dns.edns.Option``. - - *otype*, an ``int``, is the option type. + :param implementation: A subclass of :py:class:`dns.edns.Option`. + :param otype: The option type. + :type otype: :py:class:`dns.edns.OptionType` """ _type_to_class[otype] = implementation diff --git a/dns/enum.py b/dns/enum.py index 3df382b9..ca3c62f0 100644 --- a/dns/enum.py +++ b/dns/enum.py @@ -72,15 +72,11 @@ class IntEnum(enum.IntEnum): def make(cls: type[TIntEnum], value: int | str) -> TIntEnum: """Convert text or a value into an enumerated type, if possible. - *value*, the ``int`` or ``str`` to convert. - - Raises a class-specific exception if a ``str`` is provided that - cannot be converted. - - Raises ``ValueError`` if the value is out of range. - - Returns an enumeration from the calling class corresponding to the - value, if one is defined, or an ``int`` otherwise. + :param value: The value to convert. + :type value: int or str + :raises ValueError: If the value is out of range. + :returns: An enumeration from the calling class corresponding to the + value, if one is defined, or an ``int`` otherwise. """ if isinstance(value, str): diff --git a/dns/flags.py b/dns/flags.py index 84a6bb31..8eb2bc83 100644 --- a/dns/flags.py +++ b/dns/flags.py @@ -70,7 +70,7 @@ def from_text(text: str) -> int: """Convert a space-separated list of flag text values into a flags value. - Returns an ``int`` + :rtype: int """ return _from_text(text, Flag) @@ -80,7 +80,7 @@ def to_text(flags: int) -> str: """Convert a flags value into a space-separated list of flag text values. - Returns a ``str``. + :rtype: str """ return _to_text(flags, Flag) @@ -90,7 +90,7 @@ def edns_from_text(text: str) -> int: """Convert a space-separated list of EDNS flag text values into a EDNS flags value. - Returns an ``int`` + :rtype: int """ return _from_text(text, EDNSFlag) @@ -100,7 +100,7 @@ def edns_to_text(flags: int) -> str: """Convert an EDNS flags value into a space-separated list of EDNS flag text values. - Returns a ``str``. + :rtype: str """ return _to_text(flags, EDNSFlag) diff --git a/dns/grange.py b/dns/grange.py index 5c1bdb81..7a217f8d 100644 --- a/dns/grange.py +++ b/dns/grange.py @@ -24,9 +24,9 @@ def from_text(text: str) -> tuple[int, int, int]: """Convert the text form of a range in a ``$GENERATE`` statement to an integer. - *text*, a ``str``, the textual range in ``$GENERATE`` form. - - Returns a tuple of three ``int`` values ``(start, stop, step)``. + :param text: The textual range in ``$GENERATE`` form. + :type text: str + :rtype: tuple[int, int, int] """ start = -1 diff --git a/dns/inet.py b/dns/inet.py index 7db021bd..8d80c2f9 100644 --- a/dns/inet.py +++ b/dns/inet.py @@ -33,14 +33,12 @@ AF_INET6 = socket.AF_INET6 def inet_pton(family: int, text: str) -> bytes: """Convert the textual form of a network address into its binary form. - *family* is an ``int``, the address family. - - *text* is a ``str``, the textual address. - - Raises ``NotImplementedError`` if the address family specified is not - implemented. - - Returns a ``bytes``. + :param family: The address family. + :type family: int + :param text: The textual address. + :type text: str + :raises NotImplementedError: If the address family is not implemented. + :rtype: bytes """ if family == AF_INET: @@ -54,14 +52,12 @@ def inet_pton(family: int, text: str) -> bytes: def inet_ntop(family: int, address: bytes) -> str: """Convert the binary form of a network address into its textual form. - *family* is an ``int``, the address family. - - *address* is a ``bytes``, the network address in binary form. - - Raises ``NotImplementedError`` if the address family specified is not - implemented. - - Returns a ``str``. + :param family: The address family. + :type family: int + :param address: The network address in binary form. + :type address: bytes + :raises NotImplementedError: If the address family is not implemented. + :rtype: str """ if family == AF_INET: @@ -75,12 +71,10 @@ def inet_ntop(family: int, address: bytes) -> str: def af_for_address(text: str) -> int: """Determine the address family of a textual-form network address. - *text*, a ``str``, the textual address. - - Raises ``ValueError`` if the address family cannot be determined - from the input. - - Returns an ``int``. + :param text: The textual address. + :type text: str + :raises ValueError: If the address family cannot be determined. + :rtype: int """ try: @@ -97,12 +91,10 @@ def af_for_address(text: str) -> int: def is_multicast(text: str) -> bool: """Is the textual-form network address a multicast address? - *text*, a ``str``, the textual address. - - Raises ``ValueError`` if the address family cannot be determined - from the input. - - Returns a ``bool``. + :param text: The textual address. + :type text: str + :raises ValueError: If the address family cannot be determined. + :rtype: bool """ try: @@ -119,9 +111,9 @@ def is_multicast(text: str) -> bool: def is_address(text: str) -> bool: """Is the specified string an IPv4 or IPv6 address? - *text*, a ``str``, the textual address. - - Returns a ``bool``. + :param text: The textual address. + :type text: str + :rtype: bool """ try: @@ -182,9 +174,9 @@ def canonicalize(text: str) -> str: """Verify that *address* is a valid text form IPv4 or IPv6 address and return its canonical text form. IPv6 addresses with scopes are rejected. - *text*, a ``str``, the address in textual form. - - Raises ``ValueError`` if the text is not valid. + :param text: The address in textual form. + :type text: str + :raises ValueError: If the text is not a valid address. """ try: return dns.ipv6.canonicalize(text) diff --git a/dns/ipv4.py b/dns/ipv4.py index a7161bc7..57e342b6 100644 --- a/dns/ipv4.py +++ b/dns/ipv4.py @@ -25,9 +25,9 @@ import dns.exception def inet_ntoa(address: bytes) -> str: """Convert an IPv4 address in binary form to text form. - *address*, a ``bytes``, the IPv4 address in binary form. - - Returns a ``str``. + :param address: The IPv4 address in binary form. + :type address: bytes + :rtype: str """ if len(address) != 4: @@ -38,9 +38,9 @@ def inet_ntoa(address: bytes) -> str: def inet_aton(text: str | bytes) -> bytes: """Convert an IPv4 address in text form to binary form. - *text*, a ``str`` or ``bytes``, the IPv4 address in textual form. - - Returns a ``bytes``. + :param text: The IPv4 address in textual form. + :type text: str or bytes + :rtype: bytes """ if not isinstance(text, bytes): @@ -67,9 +67,9 @@ def canonicalize(text: str | bytes) -> str: """Verify that *address* is a valid text form IPv4 address and return its canonical text form. - *text*, a ``str`` or ``bytes``, the IPv4 address in textual form. - - Raises ``dns.exception.SyntaxError`` if the text is not valid. + :param text: The IPv4 address in textual form. + :type text: str or bytes + :raises dns.exception.SyntaxError: If the text is not valid. """ # Note that inet_aton() only accepts canonial form, but we still run through # inet_ntoa() to ensure the output is a str. diff --git a/dns/ipv6.py b/dns/ipv6.py index b464add6..f80f1739 100644 --- a/dns/ipv6.py +++ b/dns/ipv6.py @@ -29,10 +29,10 @@ _leading_zero = re.compile(r"0+([0-9a-f]+)") def inet_ntoa(address: bytes) -> str: """Convert an IPv6 address in binary form to text form. - *address*, a ``bytes``, the IPv6 address in binary form. - - Raises ``ValueError`` if the address isn't 16 bytes long. - Returns a ``str``. + :param address: The IPv6 address in binary form. + :type address: bytes + :raises ValueError: If the address is not 16 bytes long. + :rtype: str """ if len(address) != 16: @@ -103,12 +103,12 @@ _colon_colon_end = re.compile(rb".*::$") def inet_aton(text: str | bytes, ignore_scope: bool = False) -> bytes: """Convert an IPv6 address in text form to binary form. - *text*, a ``str`` or ``bytes``, the IPv6 address in textual form. - - *ignore_scope*, a ``bool``. If ``True``, a scope will be ignored. - If ``False``, the default, it is an error for a scope to be present. - - Returns a ``bytes``. + :param text: The IPv6 address in textual form. + :type text: str or bytes + :param ignore_scope: If ``True``, a scope is ignored; if ``False`` + (the default), a scope is an error. + :type ignore_scope: bool + :rtype: bytes """ # @@ -197,9 +197,9 @@ _mapped_prefix = b"\x00" * 10 + b"\xff\xff" def is_mapped(address: bytes) -> bool: """Is the specified address a mapped IPv4 address? - *address*, a ``bytes`` is an IPv6 address in binary form. - - Returns a ``bool``. + :param address: An IPv6 address in binary form. + :type address: bytes + :rtype: bool """ return address.startswith(_mapped_prefix) @@ -209,8 +209,8 @@ def canonicalize(text: str | bytes) -> str: """Verify that *address* is a valid text form IPv6 address and return its canonical text form. Addresses with scopes are rejected. - *text*, a ``str`` or ``bytes``, the IPv6 address in textual form. - - Raises ``dns.exception.SyntaxError`` if the text is not valid. + :param text: The IPv6 address in textual form. + :type text: str or bytes + :raises dns.exception.SyntaxError: If the text is not valid. """ return inet_ntoa(inet_aton(text)) diff --git a/dns/message.py b/dns/message.py index 4436e114..8b984c27 100644 --- a/dns/message.py +++ b/dns/message.py @@ -87,7 +87,7 @@ class Truncated(dns.exception.DNSException): def message(self): """As much of the message as could be processed. - Returns a ``dns.message.Message``. + :rtype: :py:class:`dns.message.Message` """ return self.kwargs["message"] @@ -236,10 +236,9 @@ class Message: The *origin*, *relativize*, and any other keyword arguments are passed to the RRset ``to_text()`` method. - *style*, a :py:class:`dns.rdataset.RdatasetStyle` or ``None`` (the default). If - specified, the style overrides the other parameters. - - Returns a ``str``. + :param style: If specified, overrides *origin* and *relativize*. + :type style: :py:class:`dns.rdataset.RdatasetStyle` or ``None`` + :rtype: str """ if style is None: kw = kw.copy() @@ -251,10 +250,9 @@ class Message: def to_styled_text(self, style: MessageStyle) -> str: """Convert the message to styled text. - *style*, a :py:class:`dns.rdataset.RdatasetStyle` or ``None`` (the default). If - specified, the style overrides the other parameters. - - Returns a ``str``. + :param style: The style to use for formatting. + :type style: :py:class:`dns.message.MessageStyle` + :rtype: str """ s = io.StringIO() @@ -288,7 +286,7 @@ class Message: """Two messages are equal if they have the same content in the header, question, answer, and authority sections. - Returns a ``bool``. + :rtype: bool """ if not isinstance(other, Message): @@ -311,10 +309,11 @@ class Message: return not self.__eq__(other) def is_response(self, other: "Message") -> bool: - """Is *other*, also a ``dns.message.Message``, a response to this - message? + """Is *other* a response to this message? - Returns a ``bool``. + :param other: The message to check. + :type other: :py:class:`dns.message.Message` + :rtype: bool """ if ( @@ -352,11 +351,9 @@ class Message: """Return the "section number" of the specified section for use in indexing. - *section* is one of the section attributes of this message. - - Raises ``ValueError`` if the section isn't known. - - Returns an ``int``. + :param section: One of the section attributes of this message. + :raises ValueError: If the section is not known. + :rtype: int """ for i, our_section in enumerate(self.sections): @@ -368,12 +365,9 @@ class Message: """Return the section list associated with the specified section number. - *number* is a section number `int` or the text form of a section - name. - - Raises ``ValueError`` if the section isn't known. - - Returns a ``list``. + :param number: A section number (``int``) or text name of a section. + :raises ValueError: If the section is not known. + :rtype: list """ section = self._section_enum.make(number) @@ -393,42 +387,32 @@ class Message: ) -> dns.rrset.RRset: """Find the RRset with the given attributes in the specified section. - *section*, an ``int`` section number, a ``str`` section name, or one of - the section attributes of this message. This specifies the - the section of the message to search. For example:: + *section* may be an ``int`` section number, a ``str`` section name, or + one of the section list attributes of this message. For example:: my_message.find_rrset(my_message.answer, name, rdclass, rdtype) my_message.find_rrset(dns.message.ANSWER, name, rdclass, rdtype) my_message.find_rrset("ANSWER", name, rdclass, rdtype) - *name*, a ``dns.name.Name`` or ``str``, the name of the RRset. - - *rdclass*, an ``int`` or ``str``, the class of the RRset. - - *rdtype*, an ``int`` or ``str``, the type of the RRset. - - *covers*, an ``int`` or ``str``, the covers value of the RRset. - The default is ``dns.rdatatype.NONE``. - - *deleting*, an ``int``, ``str``, or ``None``, the deleting value of the - RRset. The default is ``None``. - - *create*, a ``bool``. If ``True``, create the RRset if it is not found. - The created RRset is appended to *section*. - - *force_unique*, a ``bool``. If ``True`` and *create* is also ``True``, - create a new RRset regardless of whether a matching RRset exists - already. The default is ``False``. This is useful when creating - DDNS Update messages, as order matters for them. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - Raises ``KeyError`` if the RRset was not found and create was - ``False``. - - Returns a ``dns.rrset.RRset object``. + :param name: The owner name. + :type name: :py:class:`dns.name.Name` or ``str`` + :param rdclass: The rdata class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or ``str`` + :param rdtype: The rdata type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param covers: The covered type; default is ``dns.rdatatype.NONE``. + :type covers: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param deleting: The deleting value; default is ``None``. + :type deleting: :py:class:`dns.rdataclass.RdataClass`, ``str``, or ``None`` + :param create: If ``True``, create and append the RRset if not found. + :type create: bool + :param force_unique: If ``True`` and *create* is ``True``, always create + a new RRset even if a matching one exists. Useful for DDNS updates. + :type force_unique: bool + :param idna_codec: The IDNA encoder/decoder. Defaults to IDNA 2003. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :raises KeyError: If the RRset was not found and *create* is ``False``. + :rtype: :py:class:`dns.rrset.RRset` """ if isinstance(section, int): @@ -478,41 +462,31 @@ class Message: ) -> dns.rrset.RRset | None: """Get the RRset with the given attributes in the specified section. - If the RRset is not found, None is returned. - - *section*, an ``int`` section number, a ``str`` section name, or one of - the section attributes of this message. This specifies the - the section of the message to search. For example:: - - my_message.get_rrset(my_message.answer, name, rdclass, rdtype) - my_message.get_rrset(dns.message.ANSWER, name, rdclass, rdtype) - my_message.get_rrset("ANSWER", name, rdclass, rdtype) - - *name*, a ``dns.name.Name`` or ``str``, the name of the RRset. - - *rdclass*, an ``int`` or ``str``, the class of the RRset. - - *rdtype*, an ``int`` or ``str``, the type of the RRset. - - *covers*, an ``int`` or ``str``, the covers value of the RRset. - The default is ``dns.rdatatype.NONE``. - - *deleting*, an ``int``, ``str``, or ``None``, the deleting value of the - RRset. The default is ``None``. - - *create*, a ``bool``. If ``True``, create the RRset if it is not found. - The created RRset is appended to *section*. - - *force_unique*, a ``bool``. If ``True`` and *create* is also ``True``, - create a new RRset regardless of whether a matching RRset exists - already. The default is ``False``. This is useful when creating - DDNS Update messages, as order matters for them. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - Returns a ``dns.rrset.RRset object`` or ``None``. + Like :py:meth:`find_rrset` but returns ``None`` instead of raising + :py:exc:`KeyError` when the RRset is not found. + + *section* may be an ``int`` section number, a ``str`` section name, or + one of the section list attributes of this message. + + :param name: The owner name. + :type name: :py:class:`dns.name.Name` or ``str`` + :param rdclass: The rdata class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or ``str`` + :param rdtype: The rdata type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param covers: The covered type; default is ``dns.rdatatype.NONE``. + :type covers: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param deleting: The deleting value; default is ``None``. + :type deleting: :py:class:`dns.rdataclass.RdataClass`, ``str``, or ``None`` + :param create: If ``True``, create and append the RRset if not found. + :type create: bool + :param force_unique: If ``True`` and *create* is ``True``, always create + a new RRset even if a matching one exists. + :type force_unique: bool + :param idna_codec: The IDNA encoder/decoder. Defaults to IDNA 2003. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :returns: The matching RRset, or ``None`` if not found. + :rtype: :py:class:`dns.rrset.RRset` or ``None`` """ try: @@ -534,13 +508,12 @@ class Message: def section_count(self, section: SectionType) -> int: """Returns the number of records in the specified section. - *section*, an ``int`` section number, a ``str`` section name, or one of - the section attributes of this message. This specifies the - the section of the message to count. For example:: + :param section: An ``int`` section number, a ``str`` section name, or + one of the section attributes of this message. For example:: - my_message.section_count(my_message.answer) - my_message.section_count(dns.message.ANSWER) - my_message.section_count("ANSWER") + my_message.section_count(my_message.answer) + my_message.section_count(dns.message.ANSWER) + my_message.section_count("ANSWER") """ if isinstance(section, int): @@ -602,38 +575,30 @@ class Message: prefer_truncation: bool = False, **kw: Any, ) -> bytes: - """Return a string containing the message in DNS compressed wire - format. + """Return the message in DNS compressed wire format. Additional keyword arguments are passed to the RRset ``to_wire()`` method. - *origin*, a ``dns.name.Name`` or ``None``, the origin to be appended - to any relative names. If ``None``, and the message has an origin - attribute that is not ``None``, then it will be used. - - *max_size*, an ``int``, the maximum size of the wire format - output; default is 0, which means "the message's request - payload, if nonzero, or 65535". - - *multi*, a ``bool``, should be set to ``True`` if this message is - part of a multiple message sequence. - - *tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the - ongoing TSIG context, used when signing zone transfers. - - *prepend_length*, a ``bool``, should be set to ``True`` if the caller - wants the message length prepended to the message itself. This is - useful for messages sent over TCP, TLS (DoT), or QUIC (DoQ). - - *prefer_truncation*, a ``bool``, should be set to ``True`` if the caller - wants the message to be truncated if it would otherwise exceed the - maximum length. If the truncation occurs before the additional section, - the TC bit will be set. - - Raises ``dns.exception.TooBig`` if *max_size* was exceeded. - - Returns a ``bytes``. + :param origin: Origin to append to relative names. If ``None``, the + message's own origin (if any) is used. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param max_size: Maximum wire format size; 0 means use the request + payload or 65535. + :type max_size: int + :param multi: ``True`` if this message is part of a multi-message sequence. + :type multi: bool + :param tsig_ctx: Ongoing TSIG context for zone transfer signing. + :param prepend_length: If ``True``, prepend the 2-byte message length + (useful for TCP/TLS/QUIC). + :type prepend_length: bool + :param prefer_truncation: If ``True``, truncate instead of raising when + the message exceeds *max_size*. Sets TC if truncation is before the + additional section. + :type prefer_truncation: bool + :raises dns.exception.TooBig: If *max_size* is exceeded and + *prefer_truncation* is ``False``. + :rtype: bytes """ if origin is None and self.origin is not None: @@ -712,38 +677,28 @@ class Message: other_data: bytes = b"", algorithm: dns.name.Name | str = dns.tsig.default_algorithm, ) -> None: - """When sending, a TSIG signature using the specified key - should be added. - - *keyring*, a ``dict``, ``callable`` or ``dns.tsig.Key``, is either - the TSIG keyring or key to use. - - The format of a keyring dict is a mapping from TSIG key name, as - ``dns.name.Name`` to ``dns.tsig.Key`` or a TSIG secret, a ``bytes``. - If a ``dict`` *keyring* is specified but a *keyname* is not, the key - used will be the first key in the *keyring*. Note that the order of - keys in a dictionary is not defined, so applications should supply a - keyname when a ``dict`` keyring is used, unless they know the keyring - contains only one key. If a ``callable`` keyring is specified, the - callable will be called with the message and the keyname, and is - expected to return a key. - - *keyname*, a ``dns.name.Name``, ``str`` or ``None``, the name of - this TSIG key to use; defaults to ``None``. If *keyring* is a - ``dict``, the key must be defined in it. If *keyring* is a - ``dns.tsig.Key``, this is ignored. - - *fudge*, an ``int``, the TSIG time fudge. - - *original_id*, an ``int``, the TSIG original id. If ``None``, - the message's id is used. - - *tsig_error*, an ``int``, the TSIG error code. - - *other_data*, a ``bytes``, the TSIG other data. - - *algorithm*, a ``dns.name.Name`` or ``str``, the TSIG algorithm to use. This is - only used if *keyring* is a ``dict``, and the key entry is a ``bytes``. + """Arrange for a TSIG signature to be added when sending. + + :param keyring: The TSIG keyring or key. A ``dict`` maps + :py:class:`dns.name.Name` keys to :py:class:`dns.tsig.Key` objects + or ``bytes`` secrets. If a ``dict`` is given without *keyname*, the + first key in the dict is used. A callable is invoked with the message + and *keyname* and must return a key. + :type keyring: dict, callable, or :py:class:`dns.tsig.Key` + :param keyname: The TSIG key name. Ignored if *keyring* is a + :py:class:`dns.tsig.Key`. Defaults to ``None``. + :type keyname: :py:class:`dns.name.Name`, ``str``, or ``None`` + :param fudge: The TSIG time fudge. + :type fudge: int + :param original_id: The TSIG original id. Defaults to the message id. + :type original_id: int or ``None`` + :param tsig_error: The TSIG error code. + :type tsig_error: int + :param other_data: The TSIG other data. + :type other_data: bytes + :param algorithm: The TSIG algorithm. Only used when *keyring* is a + ``dict`` and the key entry is ``bytes``. + :type algorithm: :py:class:`dns.name.Name` or ``str`` """ if isinstance(keyring, dns.tsig.Key): @@ -824,25 +779,24 @@ class Message: ) -> None: """Configure EDNS behavior. - *edns*, an ``int``, is the EDNS level to use. Specifying ``None``, ``False``, - or ``-1`` means "do not use EDNS", and in this case the other parameters are - ignored. Specifying ``True`` is equivalent to specifying 0, i.e. "use EDNS0". - - *ednsflags*, an ``int``, the EDNS flag values. - - *payload*, an ``int``, is the EDNS sender's payload field, which is the maximum - size of UDP datagram the sender can handle. I.e. how big a response to this - message can be. - - *request_payload*, an ``int``, is the EDNS payload size to use when sending this - message. If not specified, defaults to the value of *payload*. - - *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS options. - - *pad*, a non-negative ``int``. If 0, the default, do not pad; otherwise add - padding bytes to make the message size a multiple of *pad*. Note that if - padding is non-zero, an EDNS PADDING option will always be added to the - message. + :param edns: The EDNS level to use. Specifying ``None``, ``False``, or + ``-1`` means "do not use EDNS" (other parameters are ignored). + Specifying ``True`` is equivalent to specifying 0 (use EDNS0). + :type edns: int or ``None`` + :param ednsflags: The EDNS flag values. + :type ednsflags: int + :param payload: The EDNS sender's payload field — the maximum UDP + datagram size the sender can handle (i.e. how big a response can be). + :type payload: int + :param request_payload: The EDNS payload size to use when sending. + Defaults to the value of *payload*. + :type request_payload: int or ``None`` + :param options: The EDNS options. + :type options: list of :py:class:`dns.edns.Option` or ``None`` + :param pad: If 0 (the default), do not pad; otherwise add padding bytes + to make the message size a multiple of *pad*. When nonzero, an EDNS + PADDING option is always added. + :type pad: int """ if edns is None or edns is False: @@ -906,10 +860,10 @@ class Message: def want_dnssec(self, wanted: bool = True) -> None: """Enable or disable 'DNSSEC desired' flag in requests. - *wanted*, a ``bool``. If ``True``, then DNSSEC data is - desired in the response, EDNS is enabled if required, and then - the DO bit is set. If ``False``, the DO bit is cleared if - EDNS is enabled. + :param wanted: If ``True``, DNSSEC data is desired in the response, + EDNS is enabled if required, and the DO bit is set. If ``False``, + the DO bit is cleared if EDNS is enabled. + :type wanted: bool """ if wanted: @@ -920,7 +874,7 @@ class Message: def rcode(self) -> dns.rcode.Rcode: """Return the rcode. - Returns a ``dns.rcode.Rcode``. + :rtype: :py:class:`dns.rcode.Rcode` """ return dns.rcode.from_flags(int(self.flags), int(self.ednsflags)) @@ -938,14 +892,15 @@ class Message: def opcode(self) -> dns.opcode.Opcode: """Return the opcode. - Returns a ``dns.opcode.Opcode``. + :rtype: :py:class:`dns.opcode.Opcode` """ return dns.opcode.from_flags(int(self.flags)) def set_opcode(self, opcode: dns.opcode.Opcode) -> None: """Set the opcode. - *opcode*, a ``dns.opcode.Opcode``, is the opcode to set. + :param opcode: The opcode to set. + :type opcode: :py:class:`dns.opcode.Opcode` """ self.flags &= 0x87FF self.flags |= dns.opcode.to_flags(opcode) @@ -1024,17 +979,12 @@ class QueryMessage(Message): """Follow the CNAME chain in the response to determine the answer RRset. - Raises ``dns.message.NotQueryResponse`` if the message is not - a response. - - Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long. - - Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN - but an answer was found. - - Raises ``dns.exception.FormError`` if the question count is not 1. - - Returns a ChainingResult object. + :raises dns.message.NotQueryResponse: If the message is not a response. + :raises dns.message.ChainTooLong: If the CNAME chain is too long. + :raises dns.message.AnswerForNXDOMAIN: If the rcode is NXDOMAIN but + an answer was found. + :raises dns.exception.FormError: If the question count is not 1. + :rtype: :py:class:`dns.message.ChainingResult` """ if self.flags & dns.flags.QR == 0: raise NotQueryResponse @@ -1100,15 +1050,11 @@ class QueryMessage(Message): """Return the canonical name of the first name in the question section. - Raises ``dns.message.NotQueryResponse`` if the message is not - a response. - - Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long. - - Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN - but an answer was found. - - Raises ``dns.exception.FormError`` if the question count is not 1. + :raises dns.message.NotQueryResponse: If the message is not a response. + :raises dns.message.ChainTooLong: If the CNAME chain is too long. + :raises dns.message.AnswerForNXDOMAIN: If the rcode is NXDOMAIN but + an answer was found. + :raises dns.exception.FormError: If the question count is not 1. """ return self.resolve_chaining().canonical_name @@ -1341,59 +1287,43 @@ def from_wire( ) -> Message: """Convert a DNS wire format message into a message object. - *keyring*, a ``dns.tsig.Key``, ``dict``, ``bool``, or ``None``, the key or keyring - to use if the message is signed. If ``None`` or ``True``, then trying to decode - a message with a TSIG will fail as it cannot be validated. If ``False``, then - TSIG validation is disabled. - - *request_mac*, a ``bytes`` or ``None``. If the message is a response to a - TSIG-signed request, *request_mac* should be set to the MAC of that request. - - *xfr*, a ``bool``, should be set to ``True`` if this message is part of a zone - transfer. - - *origin*, a ``dns.name.Name`` or ``None``. If the message is part of a zone - transfer, *origin* should be the origin name of the zone. If not ``None``, names - will be relativized to the origin. - - *tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the ongoing TSIG - context, used when validating zone transfers. - - *multi*, a ``bool``, should be set to ``True`` if this message is part of a multiple - message sequence. - - *question_only*, a ``bool``. If ``True``, read only up to the end of the question - section. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - message. - - *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if the TC bit is - set. - - *continue_on_error*, a ``bool``. If ``True``, try to continue parsing even if - errors occur. Erroneous rdata will be ignored. Errors will be accumulated as a - list of MessageError objects in the message's ``errors`` attribute. This option is - recommended only for DNS analysis tools, or for use in a server as part of an error - handling path. The default is ``False``. - - Raises ``dns.message.ShortHeader`` if the message is less than 12 octets long. - - Raises ``dns.message.TrailingJunk`` if there were octets in the message past the end - of the proper DNS message, and *ignore_trailing* is ``False``. - - Raises ``dns.message.BadEDNS`` if an OPT record was in the wrong section, or - occurred more than once. - - Raises ``dns.message.BadTSIG`` if a TSIG record was not the last record of the - additional data section. - - Raises ``dns.message.Truncated`` if the TC flag is set and *raise_on_truncation* is - ``True``. - - Returns a ``dns.message.Message``. + :param keyring: The key or keyring for TSIG validation. ``None`` or + ``True`` causes TSIG-signed messages to fail; ``False`` disables + validation. + :type keyring: :py:class:`dns.tsig.Key`, dict, bool, or ``None`` + :param request_mac: MAC of the TSIG-signed request this message responds + to, if any. + :type request_mac: bytes or ``None`` + :param xfr: ``True`` if this message is part of a zone transfer. + :type xfr: bool + :param origin: Zone origin for zone transfers; names are relativized to + this if not ``None``. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param tsig_ctx: Ongoing TSIG context for zone transfer validation. + :param multi: ``True`` if this message is part of a multi-message sequence. + :type multi: bool + :param question_only: If ``True``, read only the question section. + :type question_only: bool + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param ignore_trailing: If ``True``, ignore trailing octets after the + message. + :type ignore_trailing: bool + :param raise_on_truncation: If ``True``, raise + :py:exc:`dns.message.Truncated` when the TC bit is set. + :type raise_on_truncation: bool + :param continue_on_error: If ``True``, try to continue parsing on errors + and accumulate them in the message's ``errors`` attribute. + :type continue_on_error: bool + :raises dns.message.ShortHeader: If the message is less than 12 octets. + :raises dns.message.TrailingJunk: If trailing octets are present and + *ignore_trailing* is ``False``. + :raises dns.message.BadEDNS: If an OPT record is in the wrong section. + :raises dns.message.BadTSIG: If a TSIG record is not the last additional + record. + :raises dns.message.Truncated: If the TC flag is set and + *raise_on_truncation* is ``True``. + :rtype: :py:class:`dns.message.Message` """ # We permit None for request_mac solely for backwards compatibility @@ -1699,28 +1629,21 @@ def from_text( facilitate reading multiple messages from a single file with ``dns.message.from_file()``. - *text*, a ``str``, the text format message. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put - into its own rrset. The default is ``False``. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - Raises ``dns.message.UnknownHeaderField`` if a header is unknown. - - Raises ``dns.exception.SyntaxError`` if the text is badly formed. - - Returns a ``dns.message.Message object`` + :param text: The text format message. + :type text: str + :param idna_codec: The IDNA encoder/decoder. Defaults to IDNA 2003. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param origin: The origin to use for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param relativize: If ``True``, names will be relativized. + :type relativize: bool + :param relativize_to: The origin to relativize to. Defaults to *origin*. + :type relativize_to: :py:class:`dns.name.Name` or ``None`` + :raises dns.message.UnknownHeaderField: If a header field is unknown. + :raises dns.exception.SyntaxError: If the text is badly formed. + :rtype: :py:class:`dns.message.Message` """ # 'text' can also be a file, but we don't publish that fact @@ -1742,21 +1665,14 @@ def from_file( Message blocks are separated by a single blank line. - *f*, a ``file`` or ``str``. If *f* is text, it is treated as the - pathname of a file to open. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put - into its own rrset. The default is ``False``. - - Raises ``dns.message.UnknownHeaderField`` if a header is unknown. - - Raises ``dns.exception.SyntaxError`` if the text is badly formed. - - Returns a ``dns.message.Message object`` + :param f: A file object or a pathname string. + :param idna_codec: The IDNA encoder/decoder. Defaults to IDNA 2003. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :raises dns.message.UnknownHeaderField: If a header field is unknown. + :raises dns.exception.SyntaxError: If the text is badly formed. + :rtype: :py:class:`dns.message.Message` """ if isinstance(f, str): @@ -1786,57 +1702,39 @@ def make_query( ) -> QueryMessage: """Make a query message. - The query name, type, and class may all be specified either - as objects of the appropriate type, or as strings. - - The query will have a randomly chosen query id, and its DNS flags - will be set to dns.flags.RD. - - qname, a ``dns.name.Name`` or ``str``, the query name. - - *rdtype*, an ``int`` or ``str``, the desired rdata type. - - *rdclass*, an ``int`` or ``str``, the desired rdata class; the default - is class IN. - - *use_edns*, an ``int``, ``bool`` or ``None``. The EDNS level to use; the - default is ``None``. If ``None``, EDNS will be enabled only if other - parameters (*ednsflags*, *payload*, *request_payload*, or *options*) are - set. - See the description of :py:func:`dns.message.Message.use_edns()` for the - possible values for use_edns and their meanings. - - *want_dnssec*, a ``bool``. If ``True``, DNSSEC data is desired. - - *ednsflags*, an ``int``, the EDNS flag values. - - *payload*, an ``int``, is the EDNS sender's payload field, which is the - maximum size of UDP datagram the sender can handle. I.e. how big - a response to this message can be. - - *request_payload*, an ``int``, is the EDNS payload size to use when - sending this message. If not specified, defaults to the value of - *payload*. - - *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS - options. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *id*, an ``int`` or ``None``, the desired query id. The default is - ``None``, which generates a random query id. - - *flags*, an ``int``, the desired query flags. The default is - ``dns.flags.RD``. - - *pad*, a non-negative ``int``. If 0, the default, do not pad; otherwise add - padding bytes to make the message size a multiple of *pad*. Note that if - padding is non-zero, an EDNS PADDING option will always be added to the - message. - - Returns a ``dns.message.QueryMessage`` + The query name, type, and class may be specified as objects of the + appropriate type or as strings. The query id is chosen at random, and + the DNS flags are set to ``dns.flags.RD``. + + :param qname: The query name. + :type qname: :py:class:`dns.name.Name` or ``str`` + :param rdtype: The desired rdata type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param rdclass: The desired rdata class; default is IN. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or ``str`` + :param use_edns: The EDNS level; ``None`` enables EDNS only if other EDNS + parameters are set. See :py:meth:`dns.message.Message.use_edns`. + :type use_edns: int, bool, or ``None`` + :param want_dnssec: If ``True``, DNSSEC data is desired. + :type want_dnssec: bool + :param ednsflags: The EDNS flag values. + :type ednsflags: int + :param payload: The EDNS sender payload field (max UDP response size). + :type payload: int + :param request_payload: The EDNS payload size to advertise when sending. + Defaults to *payload*. + :type request_payload: int + :param options: The EDNS options. + :type options: list of :py:class:`dns.edns.Option` or ``None`` + :param idna_codec: The IDNA encoder/decoder. Defaults to IDNA 2003. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param id: The query id. Defaults to a random id. + :type id: int or ``None`` + :param flags: The query flags. Default is ``dns.flags.RD``. + :type flags: int + :param pad: If non-zero, add EDNS PADDING to make size a multiple of this. + :type pad: int + :rtype: :py:class:`dns.message.QueryMessage` """ if isinstance(qname, str): @@ -1873,8 +1771,11 @@ class CopyMode(enum.Enum): How should sections be copied when making an update response? """ + #: Copy no sections; only suitable for testing NOTHING = 0 + #: Copy only the question section, if present. QUESTION = 1 + #: Copy all sections, other than OPT and TSIG RRs. EVERYTHING = 2 @@ -1887,43 +1788,31 @@ def make_response( pad: int | None = None, copy_mode: CopyMode | None = None, ) -> Message: - """Make a message which is a response for the specified query. - The message returned is really a response skeleton; it has all of the infrastructure - required of a response, but none of the content. - - Response section(s) which are copied are shallow copies of the matching section(s) - in the query, so the query's RRsets should not be changed. - - *query*, a ``dns.message.Message``, the query to respond to. - - *recursion_available*, a ``bool``, should RA be set in the response? - - *our_payload*, an ``int``, the payload size to advertise in EDNS responses. - - *fudge*, an ``int``, the TSIG time fudge. - - *tsig_error*, an ``int``, the TSIG error. - - *pad*, a non-negative ``int`` or ``None``. If 0, the default, do not pad; otherwise - if not ``None`` add padding bytes to make the message size a multiple of *pad*. Note - that if padding is non-zero, an EDNS PADDING option will always be added to the - message. If ``None``, add padding following RFC 8467, namely if the request is - padded, pad the response to 468 otherwise do not pad. - - *copy_mode*, a ``dns.message.CopyMode`` or ``None``, determines how sections are - copied. The default, ``None`` copies sections according to the default for the - message's opcode, which is currently ``dns.message.CopyMode.QUESTION`` for all - opcodes. ``dns.message.CopyMode.QUESTION`` copies only the question section. - ``dns.message.CopyMode.EVERYTHING`` copies all sections other than OPT or TSIG - records, which are created appropriately if needed. ``dns.message.CopyMode.NOTHING`` - copies no sections; note that this mode is for server testing purposes and is - otherwise not recommended for use. In particular, ``dns.message.is_response()`` - will be ``False`` if you create a response this way and the rcode is not - ``FORMERR``, ``SERVFAIL``, ``NOTIMP``, or ``REFUSED``. - - Returns a ``dns.message.Message`` object whose specific class is appropriate for the - query. For example, if query is a ``dns.update.UpdateMessage``, the response will - be one too. + """Make a response skeleton for the specified query. + + The returned message has all required response infrastructure but no + content. Copied sections are shallow copies, so the query's RRsets + should not be changed. + + :param query: The query to respond to. + :type query: :py:class:`dns.message.Message` + :param recursion_available: If ``True``, set the RA bit. + :type recursion_available: bool + :param our_payload: The EDNS payload size to advertise. + :type our_payload: int + :param fudge: The TSIG time fudge. + :type fudge: int + :param tsig_error: The TSIG error code. + :type tsig_error: int + :param pad: If 0, no padding; if not ``None`` pad to a multiple of this + value; if ``None``, follow RFC 8467 (pad to 468 if request was padded). + :type pad: int or ``None`` + :param copy_mode: Controls which sections are copied. ``None`` uses the + default for the opcode (currently + :py:attr:`dns.message.CopyMode.QUESTION`). + :type copy_mode: :py:class:`dns.message.CopyMode` or ``None`` + :returns: A response message of the same class as *query*. + :rtype: :py:class:`dns.message.Message` """ if query.flags & dns.flags.QR: diff --git a/dns/name.py b/dns/name.py index 4fc64c85..aeb50682 100644 --- a/dns/name.py +++ b/dns/name.py @@ -148,8 +148,10 @@ _escaped_text = '"().;\\@$' def _escapify(label: bytes | str) -> str: """Escape the characters in label which need it. - @returns: the escaped string - @rtype: string""" + + :returns: the escaped string + :rtype: str + """ if isinstance(label, bytes): # Ordinary DNS label mode. Escape special characters and values # < 0x20 or > 0x7f. @@ -205,9 +207,9 @@ class IDNA2003Codec(IDNACodec): def __init__(self, strict_decode: bool = False): """Initialize the IDNA 2003 encoder/decoder. - *strict_decode* is a ``bool``. If `True`, then IDNA2003 checking - is done when decoding. This can cause failures if the name - was encoded with IDNA2008. The default is `False`. + :param bool strict_decode: If ``True``, then IDNA2003 checking + is done when decoding. This can cause failures if the name + was encoded with IDNA2008. The default is ``False``. """ super().__init__() @@ -247,26 +249,23 @@ class IDNA2008Codec(IDNACodec): ): """Initialize the IDNA 2008 encoder/decoder. - *uts_46* is a ``bool``. If True, apply Unicode IDNA - compatibility processing as described in Unicode Technical - Standard #46 (https://unicode.org/reports/tr46/). - If False, do not apply the mapping. The default is False. - - *transitional* is a ``bool``: If True, use the - "transitional" mode described in Unicode Technical Standard - #46. The default is False. This setting has no effect - in idna 3.11 and later as transitional support has been removed. - - *allow_pure_ascii* is a ``bool``. If True, then a label which - consists of only ASCII characters is allowed. This is less - strict than regular IDNA 2008, but is also necessary for mixed - names, e.g. a name with starting with "_sip._tcp." and ending - in an IDN suffix which would otherwise be disallowed. The - default is False. - - *strict_decode* is a ``bool``: If True, then IDNA2008 checking - is done when decoding. This can cause failures if the name - was encoded with IDNA2003. The default is False. + :param bool uts_46: If ``True``, apply Unicode IDNA compatibility + processing as described in Unicode Technical Standard #46 + (https://unicode.org/reports/tr46/). If ``False``, do not + apply the mapping. The default is ``False``. + :param bool transitional: If ``True``, use the "transitional" mode + described in Unicode Technical Standard #46. The default is + ``False``. This setting has no effect in idna 3.11 and later + as transitional support has been removed. + :param bool allow_pure_ascii: If ``True``, then a label which + consists of only ASCII characters is allowed. This is less + strict than regular IDNA 2008, but is also necessary for mixed + names, e.g. a name starting with ``_sip._tcp.`` and ending + in an IDN suffix which would otherwise be disallowed. The + default is ``False``. + :param bool strict_decode: If ``True``, then IDNA2008 checking + is done when decoding. This can cause failures if the name + was encoded with IDNA2003. The default is ``False``. """ super().__init__() self.uts_46 = uts_46 @@ -335,12 +334,10 @@ def _validate_labels(labels: tuple[bytes, ...]) -> None: """Check for empty labels in the middle of a label sequence, labels that are too long, and for too many labels. - Raises ``dns.name.NameTooLong`` if the name as a whole is too long. - - Raises ``dns.name.EmptyLabel`` if a label is empty (i.e. the root - label) and appears in a position other than the end of the label - sequence - + :raises dns.name.NameTooLong: if the name as a whole is too long. + :raises dns.name.EmptyLabel: if a label is empty (i.e. the root + label) and appears in a position other than the end of the label + sequence. """ l = len(labels) @@ -375,20 +372,22 @@ def _maybe_convert_to_binary(label: bytes | str) -> bytes: @dataclasses.dataclass(frozen=True) class NameStyle(BaseStyle): - """Name text styles - - *omit_final_dot* is a ``bool``. If True, don't emit the final - dot (denoting the root label) for absolute names. The default - is False. - - *idna_codec* specifies the IDNA decoder to use. The default is ``None`` - which means all text is in the standard DNS zonefile format, i.e. - punycode will not be decoded. - - If *origin* is ``None``, the default, then the name's relativity is not - altered before conversion to text. Otherwise, if *relativize* is ``True`` - the name is relativized, and if *relativize* is ``False`` the name is - derelativized. + """Name text styles. + + :param bool omit_final_dot: If ``True``, don't emit the final dot + (denoting the root label) for absolute names. The default is + ``False``. + :param idna_codec: The IDNA decoder to use. The default is ``None``, + which means all text is in the standard DNS zonefile format, i.e. + punycode will not be decoded. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param origin: If ``None`` (the default), the name's relativity is not + altered before conversion to text. Otherwise, if *relativize* is + ``True`` the name is relativized, and if *relativize* is ``False`` + the name is derelativized. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param bool relativize: Controls the direction of relativization when + *origin* is set. """ omit_final_dot: bool = False @@ -409,7 +408,10 @@ class Name: __slots__ = ["labels"] def __init__(self, labels: Iterable[bytes | str]): - """*labels* is any iterable whose values are ``str`` or ``bytes``.""" + """Initialize a DNS name. + + :param labels: An iterable whose values are ``str`` or ``bytes``. + """ blabels = [_maybe_convert_to_binary(x) for x in labels] self.labels = tuple(blabels) @@ -432,15 +434,15 @@ class Name: def is_absolute(self) -> bool: """Is the most significant label of this name the root label? - Returns a ``bool``. + :rtype: bool """ return len(self.labels) > 0 and self.labels[-1] == b"" def is_wild(self) -> bool: - """Is this name wild? (I.e. Is the least significant label '*'?) + """Is this name wild? (I.e. Is the least significant label ``'*'``?) - Returns a ``bool``. + :rtype: bool """ return len(self.labels) > 0 and self.labels[0] == b"*" @@ -448,7 +450,7 @@ class Name: def __hash__(self) -> int: """Return a case-insensitive hash of the name. - Returns an ``int``. + :rtype: int """ h = 0 @@ -461,10 +463,12 @@ class Name: """Compare two names, returning a 3-tuple ``(relation, order, nlabels)``. - *relation* describes the relation ship between the names, - and is one of: ``dns.name.NameRelation.NONE``, - ``dns.name.NameRelation.SUPERDOMAIN``, ``dns.name.NameRelation.SUBDOMAIN``, - ``dns.name.NameRelation.EQUAL``, or ``dns.name.NameRelation.COMMONANCESTOR``. + *relation* describes the relationship between the names, and is one + of: :py:attr:`dns.name.NameRelation.NONE`, + :py:attr:`dns.name.NameRelation.SUPERDOMAIN`, + :py:attr:`dns.name.NameRelation.SUBDOMAIN`, + :py:attr:`dns.name.NameRelation.EQUAL`, or + :py:attr:`dns.name.NameRelation.COMMONANCESTOR`. *order* is < 0 if *self* < *other*, > 0 if *self* > *other*, and == 0 if *self* == *other*. A relative name is always less than an @@ -487,6 +491,11 @@ class Name: example1 example2. none < 0 0 example1. example2 none > 0 0 ============= ============= =========== ===== ======= + + :param other: The name to compare with. + :type other: :py:class:`dns.name.Name` + :returns: A 3-tuple ``(relation, order, nlabels)``. + :rtype: tuple[:py:class:`dns.name.NameRelation`, int, int] """ sabs = self.is_absolute() @@ -537,9 +546,9 @@ class Name: """Is self a subdomain of other? Note that the notion of subdomain includes equality, e.g. - "dnspython.org" is a subdomain of itself. + ``dnspython.org`` is a subdomain of itself. - Returns a ``bool``. + :rtype: bool """ nr, _, _ = self.fullcompare(other) @@ -551,9 +560,9 @@ class Name: """Is self a superdomain of other? Note that the notion of superdomain includes equality, e.g. - "dnspython.org" is a superdomain of itself. + ``dnspython.org`` is a superdomain of itself. - Returns a ``bool``. + :rtype: bool """ nr, _, _ = self.fullcompare(other) @@ -564,6 +573,8 @@ class Name: def canonicalize(self) -> "Name": """Return a name which is equal to the current name, but is in DNSSEC canonical form. + + :rtype: :py:class:`dns.name.Name` """ return Name([x.lower() for x in self.labels]) @@ -615,14 +626,12 @@ class Name: ) -> str: """Convert name to DNS text format. - *omit_final_dot* is a ``bool``. If True, don't emit the final - dot (denoting the root label) for absolute names. The default - is False. - - *style*, a :py:class:`dns.name.NameStyle` or ``None`` (the default). If - specified, the style overrides the other parameters. - - Returns a ``str``. + :param bool omit_final_dot: If ``True``, don't emit the final dot + (denoting the root label) for absolute names. The default is + ``False``. + :param style: If specified, the style overrides the other parameters. + :type style: :py:class:`dns.name.NameStyle` or ``None`` + :rtype: str """ if style is None: style = NameStyle(omit_final_dot=omit_final_dot) @@ -638,11 +647,15 @@ class Name: IDN ACE labels are converted to Unicode using the specified codec. - *omit_final_dot* is a ``bool``. If True, don't emit the final - dot (denoting the root label) for absolute names. The default - is False. - - Returns a ``str``. + :param bool omit_final_dot: If ``True``, don't emit the final dot + (denoting the root label) for absolute names. The default is + ``False``. + :param idna_codec: The IDNA codec to use for decoding ACE labels. + If ``None``, the default IDNA codec is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param style: If specified, the style overrides the other parameters. + :type style: :py:class:`dns.name.NameStyle` or ``None`` + :rtype: str """ if idna_codec is None: idna_codec = IDNA_DEFAULT @@ -656,7 +669,9 @@ class Name: See the documentation for :py:class:`dns.name.NameStyle` for a description of the style parameters. - Returns a ``str``. + :param style: The style to apply. + :type style: :py:class:`dns.name.NameStyle` + :rtype: str """ name = self.choose_relativity(style.origin, style.relativize) @@ -680,14 +695,12 @@ class Name: format. All names in wire format are absolute. If the name is a relative name, then an origin must be supplied. - *origin* is a ``dns.name.Name`` or ``None``. If the name is - relative and origin is not ``None``, then origin will be appended - to the name. - - Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is - relative and no origin was provided. - - Returns a ``bytes``. + :param origin: If the name is relative and *origin* is not ``None``, + then *origin* will be appended to the name. + :type origin: :py:class:`dns.name.Name` or ``None`` + :raises dns.name.NeedAbsoluteNameOrOrigin: if the name is relative + and no origin was provided. + :rtype: bytes """ digest = self.to_wire(origin=origin, canonicalize=True) @@ -703,28 +716,24 @@ class Name: ) -> bytes | None: """Convert name to wire format, possibly compressing it. - *file* is the file where the name is emitted (typically an - io.BytesIO file). If ``None`` (the default), a ``bytes`` - containing the wire name will be returned. - - *compress*, a ``dict``, is the compression table to use. If - ``None`` (the default), names will not be compressed. Note that - the compression code assumes that compression offset 0 is the - start of *file*, and thus compression will not be correct - if this is not the case. - - *origin* is a ``dns.name.Name`` or ``None``. If the name is - relative and origin is not ``None``, then *origin* will be appended - to it. - - *canonicalize*, a ``bool``, indicates whether the name should - be canonicalized; that is, converted to a format suitable for - digesting in hashes. - - Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is - relative and no origin was provided. - - Returns a ``bytes`` or ``None``. + :param file: The file where the name is emitted (typically an + ``io.BytesIO`` file). If ``None`` (the default), a ``bytes`` + containing the wire name will be returned. + :param compress: The compression table to use. If ``None`` (the + default), names will not be compressed. Note that the compression + code assumes that compression offset 0 is the start of *file*, + and thus compression will not be correct if this is not the case. + :type compress: dict or ``None`` + :param origin: If the name is relative and *origin* is not ``None``, + then *origin* will be appended to it. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param bool canonicalize: Whether the name should be canonicalized; + that is, converted to a format suitable for digesting in hashes. + :raises dns.name.NeedAbsoluteNameOrOrigin: if the name is relative + and no origin was provided. + :returns: ``None`` if *file* is provided, otherwise the wire format + as ``bytes``. + :rtype: bytes or ``None`` """ if file is None: @@ -784,7 +793,7 @@ class Name: def __len__(self) -> int: """The length of the name (in labels). - Returns an ``int``. + :rtype: int """ return len(self.labels) @@ -801,12 +810,11 @@ class Name: def split(self, depth: int) -> tuple["Name", "Name"]: """Split a name into a prefix and suffix names at the specified depth. - *depth* is an ``int`` specifying the number of labels in the suffix - - Raises ``ValueError`` if *depth* was not >= 0 and <= the length of the - name. - - Returns the tuple ``(prefix, suffix)``. + :param int depth: The number of labels in the suffix. + :raises ValueError: if *depth* is not >= 0 and <= the length of the + name. + :returns: A ``(prefix, suffix)`` tuple. + :rtype: tuple[:py:class:`dns.name.Name`, :py:class:`dns.name.Name`] """ l = len(self.labels) @@ -821,10 +829,11 @@ class Name: def concatenate(self, other: "Name") -> "Name": """Return a new name which is the concatenation of self and other. - Raises ``dns.name.AbsoluteConcatenation`` if the name is - absolute and *other* is not the empty name. - - Returns a ``dns.name.Name``. + :param other: The name to concatenate. + :type other: :py:class:`dns.name.Name` + :raises dns.name.AbsoluteConcatenation: if the name is absolute and + *other* is not the empty name. + :rtype: :py:class:`dns.name.Name` """ if self.is_absolute() and len(other) > 0: @@ -841,7 +850,9 @@ class Name: ``dnspython.org.`` returns the name ``www``. Relativizing ``example.`` to origin ``dnspython.org.`` returns ``example.``. - Returns a ``dns.name.Name``. + :param origin: The origin to relativize against. + :type origin: :py:class:`dns.name.Name` + :rtype: :py:class:`dns.name.Name` """ if self.is_subdomain(origin): @@ -857,7 +868,9 @@ class Name: returns the name ``www.dnspython.org.``. Derelativizing ``example.`` to origin ``dnspython.org.`` returns ``example.``. - Returns a ``dns.name.Name``. + :param origin: The origin to append. + :type origin: :py:class:`dns.name.Name` + :rtype: :py:class:`dns.name.Name` """ if not self.is_absolute(): @@ -875,7 +888,11 @@ class Name: relativized, and if *relativize* is ``False`` the name is derelativized. - Returns a ``dns.name.Name``. + :param origin: If not ``None``, controls relativization. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param bool relativize: If ``True``, relativize; if ``False``, + derelativize. + :rtype: :py:class:`dns.name.Name` """ if origin: @@ -889,12 +906,11 @@ class Name: def parent(self) -> "Name": """Return the parent of the name. - For example, the parent of ``www.dnspython.org.`` is ``dnspython.org``. - - Raises ``dns.name.NoParent`` if the name is either the root name or the - empty name, and thus has no parent. + For example, the parent of ``www.dnspython.org.`` is ``dnspython.org.``. - Returns a ``dns.name.Name``. + :raises dns.name.NoParent: if the name is either the root name or the + empty name, and thus has no parent. + :rtype: :py:class:`dns.name.Name` """ if self == root or self == empty: @@ -902,27 +918,34 @@ class Name: return Name(self.labels[1:]) def predecessor(self, origin: "Name", prefix_ok: bool = True) -> "Name": - """Return the maximal predecessor of *name* in the DNSSEC ordering in the zone - whose origin is *origin*, or return the longest name under *origin* if the - name is origin (i.e. wrap around to the longest name, which may still be - *origin* due to length considerations. + """Return the maximal predecessor of the name in the DNSSEC ordering. + + Returns the maximal predecessor in the zone whose origin is *origin*, + or returns the longest name under *origin* if the name is *origin* + (i.e. wraps around to the longest name, which may still be *origin* + due to length considerations). The relativity of the name is preserved, so if this name is relative then the method will return a relative name, and likewise if this name is absolute then the predecessor will be absolute. - *prefix_ok* indicates if prefixing labels is allowed, and - defaults to ``True``. Normally it is good to allow this, but if computing - a maximal predecessor at a zone cut point then ``False`` must be specified. + :param origin: The zone origin. + :type origin: :py:class:`dns.name.Name` + :param bool prefix_ok: If ``True`` (the default), prefixing labels is + allowed. Specify ``False`` when computing a maximal predecessor + at a zone cut point. + :rtype: :py:class:`dns.name.Name` """ return _handle_relativity_and_call( _absolute_predecessor, self, origin, prefix_ok ) def successor(self, origin: "Name", prefix_ok: bool = True) -> "Name": - """Return the minimal successor of *name* in the DNSSEC ordering in the zone - whose origin is *origin*, or return *origin* if the successor cannot be - computed due to name length limitations. + """Return the minimal successor of the name in the DNSSEC ordering. + + Returns the minimal successor in the zone whose origin is *origin*, + or returns *origin* if the successor cannot be computed due to name + length limitations. Note that *origin* is returned in the "too long" cases because wrapping around to the origin is how NSEC records express "end of the zone". @@ -931,9 +954,12 @@ class Name: then the method will return a relative name, and likewise if this name is absolute then the successor will be absolute. - *prefix_ok* indicates if prefixing a new minimal label is allowed, and - defaults to ``True``. Normally it is good to allow this, but if computing - a minimal successor at a zone cut point then ``False`` must be specified. + :param origin: The zone origin. + :type origin: :py:class:`dns.name.Name` + :param bool prefix_ok: If ``True`` (the default), prefixing a new + minimal label is allowed. Specify ``False`` when computing a + minimal successor at a zone cut point. + :rtype: :py:class:`dns.name.Name` """ return _handle_relativity_and_call(_absolute_successor, self, origin, prefix_ok) @@ -948,21 +974,19 @@ empty = Name([]) def from_unicode( text: str, origin: Name | None = root, idna_codec: IDNACodec | None = None ) -> Name: - """Convert unicode text into a Name object. + """Convert unicode text into a :py:class:`dns.name.Name` object. Labels are encoded in IDN ACE form according to rules specified by the IDNA codec. - *text*, a ``str``, is the text to convert into a name. - - *origin*, a ``dns.name.Name``, specifies the origin to - append to non-absolute names. The default is the root name. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA encoder/decoder - is used. - - Returns a ``dns.name.Name``. + :param str text: The text to convert into a name. + :param origin: The origin to append to non-absolute names. The + default is the root name. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param idna_codec: The IDNA encoder/decoder. If ``None``, the default + IDNA encoder/decoder is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :rtype: :py:class:`dns.name.Name` """ labels = [] @@ -1030,18 +1054,17 @@ def from_text( origin: Name | None = root, idna_codec: IDNACodec | None = None, ) -> Name: - """Convert text into a Name object. - - *text*, a ``bytes`` or ``str``, is the text to convert into a name. - - *origin*, a ``dns.name.Name``, specifies the origin to - append to non-absolute names. The default is the root name. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA encoder/decoder - is used. - - Returns a ``dns.name.Name``. + """Convert text into a :py:class:`dns.name.Name` object. + + :param text: The text to convert into a name. + :type text: bytes or str + :param origin: The origin to append to non-absolute names. The + default is the root name. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param idna_codec: The IDNA encoder/decoder. If ``None``, the default + IDNA encoder/decoder is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :rtype: :py:class:`dns.name.Name` """ if isinstance(text, str): @@ -1109,16 +1132,14 @@ def from_text( def from_wire_parser(parser: dns.wirebase.Parser) -> Name: - """Convert possibly compressed wire format into a Name. - - *parser* is a dns.wirebase.Parser. - - Raises ``dns.name.BadPointer`` if a compression pointer did not - point backwards in the message. - - Raises ``dns.name.BadLabelType`` if an invalid label type was encountered. - - Returns a ``dns.name.Name`` + """Convert possibly compressed wire format into a :py:class:`dns.name.Name`. + + :param parser: The wire format parser. + :type parser: :py:class:`dns.wirebase.Parser` + :raises dns.name.BadPointer: if a compression pointer did not + point backwards in the message. + :raises dns.name.BadLabelType: if an invalid label type was encountered. + :rtype: :py:class:`dns.name.Name` """ labels = [] @@ -1142,22 +1163,18 @@ def from_wire_parser(parser: dns.wirebase.Parser) -> Name: def from_wire(message: bytes, current: int) -> tuple[Name, int]: - """Convert possibly compressed wire format into a Name. - - *message* is a ``bytes`` containing an entire DNS message in DNS - wire form. - - *current*, an ``int``, is the offset of the beginning of the name - from the start of the message - - Raises ``dns.name.BadPointer`` if a compression pointer did not - point backwards in the message. - - Raises ``dns.name.BadLabelType`` if an invalid label type was encountered. - - Returns a ``(dns.name.Name, int)`` tuple consisting of the name - that was read and the number of bytes of the wire format message - which were consumed reading it. + """Convert possibly compressed wire format into a :py:class:`dns.name.Name`. + + :param bytes message: A ``bytes`` containing an entire DNS message in DNS + wire form. + :param int current: The offset of the beginning of the name from the + start of the message. + :raises dns.name.BadPointer: if a compression pointer did not + point backwards in the message. + :raises dns.name.BadLabelType: if an invalid label type was encountered. + :returns: A tuple of the name that was read and the number of bytes of + the wire format message which were consumed reading it. + :rtype: tuple[:py:class:`dns.name.Name`, int] """ parser = dns.wirebase.Parser(message, current) diff --git a/dns/namedict.py b/dns/namedict.py index ca8b1978..9423ab32 100644 --- a/dns/namedict.py +++ b/dns/namedict.py @@ -92,10 +92,10 @@ class NameDict(MutableMapping): a superdomain of *name*. Note that *superdomain* includes matching *name* itself. - *name*, a ``dns.name.Name``, the name to find. - - Returns a ``(key, value)`` where *key* is the deepest - ``dns.name.Name``, and *value* is the value associated with *key*. + :param name: The name to find. + :type name: :py:class:`dns.name.Name` + :returns: A ``(key, value)`` tuple where *key* is the deepest + matching :py:class:`dns.name.Name`. """ depth = len(name) diff --git a/dns/node.py b/dns/node.py index 9f3fbae5..165c137d 100644 --- a/dns/node.py +++ b/dns/node.py @@ -62,8 +62,11 @@ class NodeStyle(dns.rdataset.RdatasetStyle): class NodeKind(enum.Enum): """Rdatasets in nodes""" + #: Has rdatasets not compatible with CNAME REGULAR = 0 # a.k.a "other data" + #: Has rdatasets compatible with CNAME, but no CNAME NEUTRAL = 1 + #: Has a CNAME or RRSIG(CNAME) CNAME = 2 @classmethod @@ -112,13 +115,12 @@ class Node: Each rdataset at the node is printed. Any keyword arguments to this method are passed on to the rdataset's to_text() method. - *name*, a ``dns.name.Name``, the owner name of the - rdatasets. - - *style*, a :py:class:`dns.node.NodeStyle` or ``None`` (the default). If - specified, the style overrides the other parameters except *name*. - - Returns a ``str``. + :param name: The owner name of the rdatasets. + :type name: :py:class:`dns.name.Name` + :param style: If specified, overrides the other parameters except + *name*. + :type style: :py:class:`dns.node.NodeStyle` or ``None`` + :rtype: str """ if style is None: style = NodeStyle.from_keywords(kw) @@ -129,13 +131,13 @@ class Node: Each rdataset at the node is printed. - *name*, a ``dns.name.Name``, the owner name of the - rdatasets. + :param name: The owner name of the rdatasets. + :type name: :py:class:`dns.name.Name` See the documentation for :py:class:`dns.node.NodeStyle` for a description of the style parameters. - Returns a ``str``. + :rtype: str """ s = io.StringIO() @@ -209,26 +211,18 @@ class Node: """Find an rdataset matching the specified properties in the current node. - *rdclass*, a ``dns.rdataclass.RdataClass``, the class of the rdataset. - - *rdtype*, a ``dns.rdatatype.RdataType``, the type of the rdataset. - - *covers*, a ``dns.rdatatype.RdataType``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If True, create the rdataset if it is not found. - - Raises ``KeyError`` if an rdataset of the desired type and class does - not exist and *create* is not ``True``. - - Returns a ``dns.rdataset.Rdataset``. + :param rdclass: The class of the rdataset. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param rdtype: The type of the rdataset. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :param covers: The covered type. Usually ``dns.rdatatype.NONE``, but + for SIG/RRSIG the type being covered (e.g. A, NS, SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` + :param create: If ``True``, create the rdataset if not found. + :type create: bool + :raises KeyError: If no matching rdataset exists and *create* is not + ``True``. + :rtype: :py:class:`dns.rdataset.Rdataset` """ for rds in self.rdatasets: @@ -253,22 +247,15 @@ class Node: None is returned if an rdataset of the specified type and class does not exist and *create* is not ``True``. - *rdclass*, an ``int``, the class of the rdataset. - - *rdtype*, an ``int``, the type of the rdataset. - - *covers*, an ``int``, the covered type. Usually this value is - dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or - dns.rdatatype.RRSIG, then the covers value will be the rdata - type the SIG/RRSIG covers. The library treats the SIG and RRSIG - types as if they were a family of - types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much - easier to work with than if RRSIGs covering different rdata - types were aggregated into a single RRSIG rdataset. - - *create*, a ``bool``. If True, create the rdataset if it is not found. - - Returns a ``dns.rdataset.Rdataset`` or ``None``. + :param rdclass: The class of the rdataset. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param rdtype: The type of the rdataset. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :param covers: The covered type (usually ``dns.rdatatype.NONE``). + :type covers: :py:class:`dns.rdatatype.RdataType` + :param create: If ``True``, create the rdataset if not found. + :type create: bool + :rtype: :py:class:`dns.rdataset.Rdataset` or ``None`` """ try: @@ -288,11 +275,12 @@ class Node: If a matching rdataset does not exist, it is not an error. - *rdclass*, an ``int``, the class of the rdataset. - - *rdtype*, an ``int``, the type of the rdataset. - - *covers*, an ``int``, the covered type. + :param rdclass: The class of the rdataset. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param rdtype: The type of the rdataset. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :param covers: The covered type. + :type covers: :py:class:`dns.rdatatype.RdataType` """ rds = self.get_rdataset(rdclass, rdtype, covers) @@ -308,10 +296,10 @@ class Node: in other words, this method does not store a copy of *replacement* at the node, it stores *replacement* itself. - *replacement*, a ``dns.rdataset.Rdataset``. - - Raises ``ValueError`` if *replacement* is not a - ``dns.rdataset.Rdataset``. + :param replacement: The replacement rdataset. + :type replacement: :py:class:`dns.rdataset.Rdataset` + :raises ValueError: If *replacement* is not a + :py:class:`dns.rdataset.Rdataset`. """ if not isinstance(replacement, dns.rdataset.Rdataset): diff --git a/dns/opcode.py b/dns/opcode.py index 4aac2586..c6157ffc 100644 --- a/dns/opcode.py +++ b/dns/opcode.py @@ -49,11 +49,10 @@ class UnknownOpcode(dns.exception.DNSException): def from_text(text: str) -> Opcode: """Convert text into an opcode. - *text*, a ``str``, the textual opcode - - Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown. - - Returns an ``int``. + :param text: The textual opcode. + :type text: str + :raises dns.opcode.UnknownOpcode: If the opcode is unknown. + :rtype: :py:class:`dns.opcode.Opcode` """ return Opcode.from_text(text) @@ -62,9 +61,9 @@ def from_text(text: str) -> Opcode: def from_flags(flags: int) -> Opcode: """Extract an opcode from DNS message flags. - *flags*, an ``int``, the DNS flags. - - Returns an ``int``. + :param flags: The DNS message flags. + :type flags: int + :rtype: :py:class:`dns.opcode.Opcode` """ return Opcode((flags & 0x7800) >> 11) @@ -74,9 +73,9 @@ def to_flags(value: Opcode) -> int: """Convert an opcode to a value suitable for ORing into DNS message flags. - *value*, an ``int``, the DNS opcode value. - - Returns an ``int``. + :param value: The DNS opcode value. + :type value: :py:class:`dns.opcode.Opcode` + :rtype: int """ return (value << 11) & 0x7800 @@ -85,11 +84,10 @@ def to_flags(value: Opcode) -> int: def to_text(value: Opcode) -> str: """Convert an opcode to text. - *value*, an ``int`` the opcode value, - - Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown. - - Returns a ``str``. + :param value: The opcode value. + :type value: :py:class:`dns.opcode.Opcode` + :raises dns.opcode.UnknownOpcode: If the opcode is unknown. + :rtype: str """ return Opcode.to_text(value) @@ -98,9 +96,9 @@ def to_text(value: Opcode) -> str: def is_update(flags: int) -> bool: """Is the opcode in flags UPDATE? - *flags*, an ``int``, the DNS message flags. - - Returns a ``bool``. + :param flags: The DNS message flags. + :type flags: int + :rtype: bool """ return from_flags(flags) == Opcode.UPDATE diff --git a/dns/query.py b/dns/query.py index 32476a6f..ac982c94 100644 --- a/dns/query.py +++ b/dns/query.py @@ -327,22 +327,16 @@ def make_socket( type: socket.SocketKind, source: Any | None = None, ) -> socket.socket: - """Make a socket. - - This function uses the module's ``socket_factory`` to make a socket of the - specified address family and type. - - *af*, a ``socket.AddressFamily`` or ``int`` is the address family, either - ``socket.AF_INET`` or ``socket.AF_INET6``. - - *type*, a ``socket.SocketKind`` is the type of socket, e.g. ``socket.SOCK_DGRAM``, - a datagram socket, or ``socket.SOCK_STREAM``, a stream socket. Note that the - ``proto`` attribute of a socket is always zero with this API, so a datagram socket - will always be a UDP socket, and a stream socket will always be a TCP socket. - - *source* is the source address and port to bind to, if any. The default is - ``None`` which will bind to the wildcard address and a randomly chosen port. - If not ``None``, it should be a (low-level) address tuple appropriate for *af*. + """Make a socket using the module's ``socket_factory``. + + :param af: Address family: ``socket.AF_INET`` or ``socket.AF_INET6``. + :type af: ``socket.AddressFamily`` or int + :param type: Socket type, e.g. ``socket.SOCK_DGRAM`` or + ``socket.SOCK_STREAM``. The ``proto`` is always 0, so datagram + sockets are UDP and stream sockets are TCP. + :type type: ``socket.SocketKind`` + :param source: Source address/port tuple to bind to, or ``None`` (bind + to wildcard address and random port). """ s = socket_factory(af, type, 0) try: @@ -362,29 +356,21 @@ def make_ssl_socket( server_hostname: dns.name.Name | str | None = None, source: Any | None = None, ) -> ssl.SSLSocket: - """Make a socket. - - This function uses the module's ``socket_factory`` to make a socket of the - specified address family and type. - - *af*, a ``socket.AddressFamily`` or ``int`` is the address family, either - ``socket.AF_INET`` or ``socket.AF_INET6``. - - *type*, a ``socket.SocketKind`` is the type of socket, e.g. ``socket.SOCK_DGRAM``, - a datagram socket, or ``socket.SOCK_STREAM``, a stream socket. Note that the - ``proto`` attribute of a socket is always zero with this API, so a datagram socket - will always be a UDP socket, and a stream socket will always be a TCP socket. - - If *ssl_context* is not ``None``, then it specifies the SSL context to use, - typically created with ``make_ssl_context()``. - - If *server_hostname* is not ``None``, then it is the hostname to use for server - certificate validation. A valid hostname must be supplied if *ssl_context* - requires hostname checking. - - *source* is the source address and port to bind to, if any. The default is - ``None`` which will bind to the wildcard address and a randomly chosen port. - If not ``None``, it should be a (low-level) address tuple appropriate for *af*. + """Make an SSL socket using the module's ``socket_factory``. + + :param af: Address family: ``socket.AF_INET`` or ``socket.AF_INET6``. + :type af: ``socket.AddressFamily`` or int + :param type: Socket type, e.g. ``socket.SOCK_DGRAM`` or + ``socket.SOCK_STREAM``. + :type type: ``socket.SocketKind`` + :param ssl_context: The SSL context to use, typically created with + :py:func:`make_ssl_context`. + :type ssl_context: ``ssl.SSLContext`` + :param server_hostname: The hostname for server certificate validation, + or ``None``. Required when *ssl_context* uses hostname checking. + :type server_hostname: :py:class:`dns.name.Name` or str or ``None`` + :param source: Source address/port tuple to bind to, or ``None`` (bind + to wildcard address and random port). """ sock = make_socket(af, type, source) if isinstance(server_hostname, dns.name.Name): @@ -461,55 +447,53 @@ def https( ) -> dns.message.Message: """Return the response obtained after sending a query via DNS-over-HTTPS. - *q*, a ``dns.message.Message``, the query to send. - - *where*, a ``str``, the nameserver IP address or the full URL. If an IP address is - given, the URL will be constructed using the following schema: - https://:/. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query - times out. If ``None``, the default, wait forever. - - *port*, a ``int``, the port to send the query to. The default is 443. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source - address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. The default is - 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - received message. - - *session*, an ``httpx.Client``. If provided, the client session to use to send the - queries. - - *path*, a ``str``. If *where* is an IP address, then *path* will be used to - construct the URL to send the DNS query to. - - *post*, a ``bool``. If ``True``, the default, POST method will be used. - - *bootstrap_address*, a ``str``, the IP address to use to bypass resolution. - - *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification - of the server is done using the default CA bundle; if ``False``, then no - verification is done; if a `str` then it specifies the path to a certificate file or - directory which will be used for verification. - - *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use for - resolution of hostnames in URLs. If not specified, a new resolver with a default - configuration will be used; note this is *not* the default resolver as that resolver - might have been configured to use DoH causing a chicken-and-egg problem. This - parameter only has an effect if the HTTP library is httpx. - - *family*, an ``int``, the address family. If socket.AF_UNSPEC (the default), both A - and AAAA records will be retrieved. - - *http_version*, a ``dns.query.HTTPVersion``, indicating which HTTP version to use. - - Returns a ``dns.message.Message``. + :param q: The query to send. + :type q: :py:class:`dns.message.Message` + :param where: The nameserver IP address or full URL. If an IP address is + given, the URL is constructed as + ``https://:/``. + :type where: str + :param timeout: Seconds to wait before timing out. ``None`` means wait + forever. + :type timeout: float or ``None`` + :param port: The port to send the query to. Default is 443. + :type port: int + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default is + 0. + :type source_port: int + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :param session: If provided, the client session to use to send the + queries. + :type session: ``httpx.Client`` or ``None`` + :param path: If *where* is an IP address, *path* is used to construct the + query URL. + :type path: str + :param post: If ``True`` (the default), use the POST method. + :type post: bool + :param bootstrap_address: The IP address to use to bypass resolution. + :type bootstrap_address: str or ``None`` + :param verify: If ``True``, verify the TLS certificate using default CA + roots; if ``False``, disable verification; if a ``str``, path to a + certificate file or directory. + :type verify: bool or str + :param resolver: Resolver to use for hostname resolution in URLs. If + ``None``, a new resolver with default configuration is used (not the + default resolver, to avoid a DoH chicken-and-egg problem). Only + effective when using httpx. + :type resolver: :py:class:`dns.resolver.Resolver` or ``None`` + :param family: Address family. ``socket.AF_UNSPEC`` (the default) + retrieves both A and AAAA records. + :type family: int + :param http_version: Which HTTP version to use. + :type http_version: :py:class:`dns.query.HTTPVersion` + :rtype: :py:class:`dns.message.Message` """ af, _, the_source = _destination_and_source(where, port, source, source_port, False) @@ -766,18 +750,17 @@ def send_udp( ) -> tuple[int, float]: """Send a DNS message to the specified UDP socket. - *sock*, a ``socket``. - - *what*, a ``bytes`` or ``dns.message.Message``, the message to send. - - *destination*, a destination tuple appropriate for the address family - of the socket, specifying where to send the query. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - Returns an ``(int, float)`` tuple of bytes sent and the sent time. + :param sock: The socket to use. + :type sock: socket + :param what: The message to send. + :type what: bytes or :py:class:`dns.message.Message` + :param destination: A destination tuple appropriate for the address family + of the socket. + :param expiration: The absolute time at which to raise a timeout + exception. ``None`` means no timeout. + :type expiration: float or ``None`` + :returns: A ``(bytes_sent, sent_time)`` tuple. + :rtype: tuple[int, float] """ if isinstance(what, dns.message.Message): @@ -802,51 +785,42 @@ def receive_udp( ) -> Any: """Read a DNS message from a UDP socket. - *sock*, a ``socket``. - - *destination*, a destination tuple appropriate for the address family - of the socket, specifying where the message is expected to arrive from. - When receiving a response, this would be where the associated query was - sent. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from - unexpected sources. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *keyring*, a ``dict``, the keyring to use for TSIG. - - *request_mac*, a ``bytes`` or ``None``, the MAC of the request (for TSIG). - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if - the TC bit is set. - Raises if the message is malformed, if network errors occur, of if there is a timeout. - If *destination* is not ``None``, returns a ``(dns.message.Message, float)`` - tuple of the received message and the received time. - - If *destination* is ``None``, returns a - ``(dns.message.Message, float, tuple)`` - tuple of the received message, the received time, and the address where - the message arrived from. - - *ignore_errors*, a ``bool``. If various format errors or response - mismatches occur, ignore them and keep listening for a valid response. - The default is ``False``. - - *query*, a ``dns.message.Message`` or ``None``. If not ``None`` and - *ignore_errors* is ``True``, check that the received message is a response - to this query, and if not keep listening for a valid response. + :param sock: The socket to read from. + :type sock: socket + :param destination: Destination tuple indicating where the message is + expected to arrive from (where the associated query was sent). + ``None`` means accept from any source. + :param expiration: The absolute time at which to raise a timeout + exception. ``None`` means no timeout. + :type expiration: float or ``None`` + :param ignore_unexpected: If ``True``, ignore responses from unexpected + sources. + :type ignore_unexpected: bool + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param keyring: The keyring to use for TSIG. + :type keyring: dict or ``None`` + :param request_mac: The MAC of the request (for TSIG). + :type request_mac: bytes or ``None`` + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :param raise_on_truncation: If ``True``, raise an exception if the TC + bit is set. + :type raise_on_truncation: bool + :param ignore_errors: If ``True``, ignore format errors or response + mismatches and keep listening for a valid response. + :type ignore_errors: bool + :param query: If not ``None`` and *ignore_errors* is ``True``, verify + the received message is a response to this query. + :type query: :py:class:`dns.message.Message` or ``None`` + :returns: If *destination* is not ``None``, a + ``(message, received_time)`` tuple; otherwise a + ``(message, received_time, from_address)`` tuple. + :rtype: tuple """ wire = b"" @@ -909,44 +883,40 @@ def udp( ) -> dns.message.Message: """Return the response obtained after sending a query via UDP. - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the - query times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from - unexpected sources. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if - the TC bit is set. - - *sock*, a ``socket.socket``, or ``None``, the socket to use for the - query. If ``None``, the default, a socket is created. Note that - if a socket is provided, it must be a nonblocking datagram socket, - and the *source* and *source_port* are ignored. - - *ignore_errors*, a ``bool``. If various format errors or response - mismatches occur, ignore them and keep listening for a valid response. - The default is ``False``. - - Returns a ``dns.message.Message``. + :param q: The query to send. + :type q: :py:class:`dns.message.Message` + :param where: IPv4 or IPv6 address of the nameserver. + :type where: str + :param timeout: Seconds to wait before timing out. ``None`` means wait + forever. + :type timeout: float or ``None`` + :param port: The port to send the message to. Default is 53. + :type port: int + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default + is 0. + :type source_port: int + :param ignore_unexpected: If ``True``, ignore responses from unexpected + sources. + :type ignore_unexpected: bool + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :param raise_on_truncation: If ``True``, raise an exception if the TC + bit is set. + :type raise_on_truncation: bool + :param sock: The socket to use. If ``None`` (the default), a socket is + created. If provided, must be a nonblocking datagram socket; *source* + and *source_port* are ignored. + :type sock: ``socket.socket`` or ``None`` + :param ignore_errors: If ``True``, ignore format errors or response + mismatches and keep listening for a valid response. + :type ignore_errors: bool + :rtype: :py:class:`dns.message.Message` """ wire = q.to_wire() @@ -1002,45 +972,44 @@ def udp_with_fallback( """Return the response to the query, trying UDP first and falling back to TCP if UDP results in a truncated response. - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query - times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source - address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. The default is - 0. - - *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from unexpected - sources. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - received message. - - *udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the UDP query. - If ``None``, the default, a socket is created. Note that if a socket is provided, - it must be a nonblocking datagram socket, and the *source* and *source_port* are - ignored for the UDP query. - - *tcp_sock*, a ``socket.socket``, or ``None``, the connected socket to use for the - TCP query. If ``None``, the default, a socket is created. Note that if a socket is - provided, it must be a nonblocking connected stream socket, and *where*, *source* - and *source_port* are ignored for the TCP query. - - *ignore_errors*, a ``bool``. If various format errors or response mismatches occur - while listening for UDP, ignore them and keep listening for a valid response. The - default is ``False``. - - Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True`` if and only if - TCP was used. + :param q: The query to send. + :type q: :py:class:`dns.message.Message` + :param where: IPv4 or IPv6 address of the nameserver. + :type where: str + :param timeout: Seconds to wait before timing out. ``None`` means wait + forever. + :type timeout: float or ``None`` + :param port: The port to send the message to. Default is 53. + :type port: int + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default + is 0. + :type source_port: int + :param ignore_unexpected: If ``True``, ignore responses from unexpected + sources. + :type ignore_unexpected: bool + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :param udp_sock: The socket to use for the UDP query. If ``None`` + (the default), a socket is created. If provided, must be a + nonblocking datagram socket; *source* and *source_port* are ignored. + :type udp_sock: ``socket.socket`` or ``None`` + :param tcp_sock: The connected socket to use for the TCP query. If + ``None`` (the default), a socket is created. If provided, must be a + nonblocking connected stream socket; *where*, *source* and + *source_port* are ignored. + :type tcp_sock: ``socket.socket`` or ``None`` + :param ignore_errors: If ``True``, ignore UDP format errors or response + mismatches and keep listening for a valid response. + :type ignore_errors: bool + :returns: A ``(message, used_tcp)`` tuple; *used_tcp* is ``True`` if and + only if TCP was used. + :rtype: tuple[:py:class:`dns.message.Message`, bool] """ try: response = udp( @@ -1117,15 +1086,15 @@ def send_tcp( ) -> tuple[int, float]: """Send a DNS message to the specified TCP socket. - *sock*, a ``socket``. - - *what*, a ``bytes`` or ``dns.message.Message``, the message to send. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - Returns an ``(int, float)`` tuple of bytes sent and the sent time. + :param sock: The socket to use. + :type sock: socket + :param what: The message to send. + :type what: bytes or :py:class:`dns.message.Message` + :param expiration: The absolute time at which to raise a timeout + exception. ``None`` means no timeout. + :type expiration: float or ``None`` + :returns: A ``(bytes_sent, sent_time)`` tuple. + :rtype: tuple[int, float] """ if isinstance(what, dns.message.Message): @@ -1150,27 +1119,22 @@ def receive_tcp( ) -> tuple[dns.message.Message, float]: """Read a DNS message from a TCP socket. - *sock*, a ``socket``. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *keyring*, a ``dict``, the keyring to use for TSIG. - - *request_mac*, a ``bytes`` or ``None``, the MAC of the request (for TSIG). - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - Raises if the message is malformed, if network errors occur, of if - there is a timeout. - - Returns a ``(dns.message.Message, float)`` tuple of the received message - and the received time. + :param sock: The socket to read from. + :type sock: socket + :param expiration: The absolute time at which to raise a timeout + exception. ``None`` means no timeout. + :type expiration: float or ``None`` + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param keyring: The keyring to use for TSIG. + :type keyring: dict or ``None`` + :param request_mac: The MAC of the request (for TSIG). + :type request_mac: bytes or ``None`` + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :returns: A ``(message, received_time)`` tuple. + :rtype: tuple[:py:class:`dns.message.Message`, float] """ ldata = _net_read(sock, 2, expiration) @@ -1211,34 +1175,32 @@ def tcp( ) -> dns.message.Message: """Return the response obtained after sending a query via TCP. - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the - query times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *sock*, a ``socket.socket``, or ``None``, the connected socket to use for the - query. If ``None``, the default, a socket is created. Note that - if a socket is provided, it must be a nonblocking connected stream - socket, and *where*, *port*, *source* and *source_port* are ignored. - - Returns a ``dns.message.Message``. + :param q: The query to send. + :type q: :py:class:`dns.message.Message` + :param where: IPv4 or IPv6 address of the nameserver. + :type where: str + :param timeout: Seconds to wait before timing out. ``None`` means wait + forever. + :type timeout: float or ``None`` + :param port: The port to send the message to. Default is 53. + :type port: int + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default + is 0. + :type source_port: int + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :param sock: The connected socket to use. If ``None`` (the default), a + socket is created. If provided, must be a nonblocking connected + stream socket; *where*, *port*, *source* and *source_port* are + ignored. + :type sock: ``socket.socket`` or ``None`` + :rtype: :py:class:`dns.message.Message` """ wire = q.to_wire() @@ -1335,49 +1297,43 @@ def tls( ) -> dns.message.Message: """Return the response obtained after sending a query via TLS. - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the - query times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 853. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *sock*, an ``ssl.SSLSocket``, or ``None``, the socket to use for - the query. If ``None``, the default, a socket is created. Note - that if a socket is provided, it must be a nonblocking connected - SSL stream socket, and *where*, *port*, *source*, *source_port*, - and *ssl_context* are ignored. - - *ssl_context*, an ``ssl.SSLContext``, the context to use when establishing - a TLS connection. If ``None``, the default, creates one with the default - configuration. - - *server_hostname*, a ``str`` containing the server's hostname. The - default is ``None``, which means that no hostname is known, and if an - SSL context is created, hostname checking will be disabled. - - *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification - of the server is done using the default CA bundle; if ``False``, then no - verification is done; if a `str` then it specifies the path to a certificate file or - directory which will be used for verification. - - Returns a ``dns.message.Message``. - + :param q: The query to send. + :type q: :py:class:`dns.message.Message` + :param where: IPv4 or IPv6 address of the nameserver. + :type where: str + :param timeout: Seconds to wait before timing out. ``None`` means wait + forever. + :type timeout: float or ``None`` + :param port: The port to send the message to. Default is 853. + :type port: int + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default + is 0. + :type source_port: int + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :param sock: The SSL socket to use. If ``None`` (the default), a socket + is created. If provided, must be a nonblocking connected SSL stream + socket; *where*, *port*, *source*, *source_port*, and *ssl_context* + are ignored. + :type sock: ``ssl.SSLSocket`` or ``None`` + :param ssl_context: The SSL context to use when establishing the TLS + connection. If ``None`` (the default), one is created with the + default configuration. + :type ssl_context: ``ssl.SSLContext`` or ``None`` + :param server_hostname: The server's hostname, or ``None``. If ``None`` + and an SSL context is created, hostname checking is disabled. + :type server_hostname: str or ``None`` + :param verify: If ``True``, verify the TLS certificate using default CA + roots; if ``False``, disable verification; if a ``str``, path to a + certificate file or directory. + :type verify: bool or str + :rtype: :py:class:`dns.message.Message` """ if sock: @@ -1443,43 +1399,38 @@ def quic( ) -> dns.message.Message: """Return the response obtained after sending a query via DNS-over-QUIC. - *q*, a ``dns.message.Message``, the query to send. - - *where*, a ``str``, the nameserver IP address. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query - times out. If ``None``, the default, wait forever. - - *port*, a ``int``, the port to send the query to. The default is 853. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source - address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. The default is - 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - received message. - - *connection*, a ``dns.quic.SyncQuicConnection``. If provided, the connection to use - to send the query. - - *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification - of the server is done using the default CA bundle; if ``False``, then no - verification is done; if a `str` then it specifies the path to a certificate file or - directory which will be used for verification. - - *hostname*, a ``str`` containing the server's hostname or ``None``. The default is - ``None``, which means that no hostname is known, and if an SSL context is created, - hostname checking will be disabled. This value is ignored if *url* is not - ``None``. - - *server_hostname*, a ``str`` or ``None``. This item is for backwards compatibility - only, and has the same meaning as *hostname*. - - Returns a ``dns.message.Message``. + :param q: The query to send. + :type q: :py:class:`dns.message.Message` + :param where: The nameserver IP address. + :type where: str + :param timeout: Seconds to wait before timing out. ``None`` means wait + forever. + :type timeout: float or ``None`` + :param port: The port to send the query to. Default is 853. + :type port: int + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default + is 0. + :type source_port: int + :param one_rr_per_rrset: If ``True``, put each RR into its own RRset. + :type one_rr_per_rrset: bool + :param ignore_trailing: If ``True``, ignore trailing junk at end of the + received message. + :type ignore_trailing: bool + :param connection: If provided, the QUIC connection to use. + :type connection: :py:class:`dns.quic.SyncQuicConnection` or ``None`` + :param verify: If ``True``, verify the TLS certificate using default CA + roots; if ``False``, disable verification; if a ``str``, path to a + certificate file or directory. + :type verify: bool or str + :param hostname: The server's hostname, or ``None``. If ``None`` and an + SSL context is created, hostname checking is disabled. + :type hostname: str or ``None`` + :param server_hostname: Deprecated alias for *hostname*. + :type server_hostname: str or ``None`` + :rtype: :py:class:`dns.message.Message` """ if not dns.quic.have_quic: @@ -1608,54 +1559,45 @@ def xfr( ) -> Any: """Return a generator for the responses to a zone transfer. - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *zone*, a ``dns.name.Name`` or ``str``, the name of the zone to transfer. - - *rdtype*, an ``int`` or ``str``, the type of zone transfer. The - default is ``dns.rdatatype.AXFR``. ``dns.rdatatype.IXFR`` can be - used to do an incremental transfer instead. - - *rdclass*, an ``int`` or ``str``, the class of the zone transfer. - The default is ``dns.rdataclass.IN``. - - *timeout*, a ``float``, the number of seconds to wait for each - response message. If None, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *keyring*, a ``dict``, the keyring to use for TSIG. - - *keyname*, a ``dns.name.Name`` or ``str``, the name of the TSIG - key to use. - - *relativize*, a ``bool``. If ``True``, all names in the zone will be - relativized to the zone origin. It is essential that the - relativize setting matches the one specified to - ``dns.zone.from_xfr()`` if using this generator to make a zone. - - *lifetime*, a ``float``, the total number of seconds to spend - doing the transfer. If ``None``, the default, then there is no - limit on the time the transfer may take. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *serial*, an ``int``, the SOA serial number to use as the base for - an IXFR diff sequence (only meaningful if *rdtype* is - ``dns.rdatatype.IXFR``). - - *use_udp*, a ``bool``. If ``True``, use UDP (only meaningful for IXFR). - - *keyalgorithm*, a ``dns.name.Name`` or ``str``, the TSIG algorithm to use. - - Raises on errors, and so does the generator. - - Returns a generator of ``dns.message.Message`` objects. + :param where: IPv4 or IPv6 address of the nameserver. + :type where: str + :param zone: The name of the zone to transfer. + :type zone: :py:class:`dns.name.Name` or str + :param rdtype: The type of zone transfer. Default is + ``dns.rdatatype.AXFR``; use ``dns.rdatatype.IXFR`` for incremental. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str or int + :param rdclass: The class of the zone transfer. Default is + ``dns.rdataclass.IN``. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or str or int + :param timeout: Seconds to wait for each response message. ``None`` + means wait forever. + :type timeout: float or ``None`` + :param port: The port to send the message to. Default is 53. + :type port: int + :param keyring: The keyring to use for TSIG. + :type keyring: dict or ``None`` + :param keyname: The name of the TSIG key to use. + :type keyname: :py:class:`dns.name.Name` or str or ``None`` + :param relativize: If ``True``, relativize all names to the zone origin. + Must match the setting passed to ``dns.zone.from_xfr()``. + :type relativize: bool + :param lifetime: Total seconds to spend on the transfer. ``None`` means + no limit. + :type lifetime: float or ``None`` + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default + is 0. + :type source_port: int + :param serial: SOA serial number to use as the IXFR base (only + meaningful when *rdtype* is ``dns.rdatatype.IXFR``). + :type serial: int + :param use_udp: If ``True``, use UDP (only meaningful for IXFR). + :type use_udp: bool + :param keyalgorithm: The TSIG algorithm to use. + :type keyalgorithm: :py:class:`dns.name.Name` or str + :returns: A generator of :py:class:`dns.message.Message` objects. """ class DummyTransactionManager(dns.transaction.TransactionManager): @@ -1721,38 +1663,32 @@ def inbound_xfr( """Conduct an inbound transfer and apply it via a transaction from the txn_manager. - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *txn_manager*, a ``dns.transaction.TransactionManager``, the txn_manager - for this transfer (typically a ``dns.zone.Zone``). - - *query*, the query to send. If not supplied, a default query is - constructed using information from the *txn_manager*. - - *port*, an ``int``, the port send the message to. The default is 53. - - *timeout*, a ``float``, the number of seconds to wait for each - response message. If None, the default, wait forever. - - *lifetime*, a ``float``, the total number of seconds to spend - doing the transfer. If ``None``, the default, then there is no - limit on the time the transfer may take. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *udp_mode*, a ``dns.query.UDPMode``, determines how UDP is used - for IXFRs. The default is ``dns.query.UDPMode.NEVER``, i.e. only use - TCP. Other possibilities are ``dns.query.UDPMode.TRY_FIRST``, which - means "try UDP but fallback to TCP if needed", and - ``dns.query.UDPMode.ONLY``, which means "try UDP and raise - ``dns.xfr.UseTCP`` if it does not succeed. - - Raises on errors. + :param where: IPv4 or IPv6 address of the nameserver. + :type where: str + :param txn_manager: The transaction manager for this transfer (typically + a :py:class:`dns.zone.Zone`). + :type txn_manager: :py:class:`dns.transaction.TransactionManager` + :param query: The query to send. If not supplied, a default query is + constructed from *txn_manager*. + :param port: The port to send the message to. Default is 53. + :type port: int + :param timeout: Seconds to wait for each response message. ``None`` + means wait forever. + :type timeout: float or ``None`` + :param lifetime: Total seconds to spend on the transfer. ``None`` means + no limit. + :type lifetime: float or ``None`` + :param source: Source IPv4 or IPv6 address. Default is the wildcard + address. + :type source: str or ``None`` + :param source_port: The port from which to send the message. Default + is 0. + :type source_port: int + :param udp_mode: How to use UDP for IXFRs. Default is + ``dns.query.UDPMode.NEVER`` (TCP only). ``TRY_FIRST`` tries UDP + with TCP fallback; ``ONLY`` raises :py:exc:`dns.xfr.UseTCP` if UDP + does not succeed. + :type udp_mode: :py:class:`dns.query.UDPMode` """ if query is None: query, serial = dns.xfr.make_query(txn_manager) diff --git a/dns/rcode.py b/dns/rcode.py index 0314dea0..db44cd30 100644 --- a/dns/rcode.py +++ b/dns/rcode.py @@ -81,11 +81,10 @@ class UnknownRcode(dns.exception.DNSException): def from_text(text: str) -> Rcode: """Convert text into an rcode. - *text*, a ``str``, the textual rcode or an integer in textual form. - - Raises ``dns.rcode.UnknownRcode`` if the rcode mnemonic is unknown. - - Returns a ``dns.rcode.Rcode``. + :param text: The textual rcode or an integer in textual form. + :type text: str + :raises dns.rcode.UnknownRcode: If the rcode mnemonic is unknown. + :rtype: :py:class:`dns.rcode.Rcode` """ return Rcode.from_text(text) @@ -94,13 +93,12 @@ def from_text(text: str) -> Rcode: def from_flags(flags: int, ednsflags: int) -> Rcode: """Return the rcode value encoded by flags and ednsflags. - *flags*, an ``int``, the DNS flags field. - - *ednsflags*, an ``int``, the EDNS flags field. - - Raises ``ValueError`` if rcode is < 0 or > 4095 - - Returns a ``dns.rcode.Rcode``. + :param flags: The DNS flags field. + :type flags: int + :param ednsflags: The EDNS flags field. + :type ednsflags: int + :raises ValueError: If the rcode is < 0 or > 4095. + :rtype: :py:class:`dns.rcode.Rcode` """ value = (flags & 0x000F) | ((ednsflags >> 20) & 0xFF0) @@ -108,13 +106,12 @@ def from_flags(flags: int, ednsflags: int) -> Rcode: def to_flags(value: Rcode) -> tuple[int, int]: - """Return a (flags, ednsflags) tuple which encodes the rcode. + """Return a ``(flags, ednsflags)`` tuple which encodes the rcode. - *value*, a ``dns.rcode.Rcode``, the rcode. - - Raises ``ValueError`` if rcode is < 0 or > 4095. - - Returns an ``(int, int)`` tuple. + :param value: The rcode. + :type value: :py:class:`dns.rcode.Rcode` + :raises ValueError: If the rcode is < 0 or > 4095. + :rtype: tuple[int, int] """ if value < 0 or value > 4095: @@ -127,11 +124,10 @@ def to_flags(value: Rcode) -> tuple[int, int]: def to_text(value: Rcode, tsig: bool = False) -> str: """Convert rcode into text. - *value*, a ``dns.rcode.Rcode``, the rcode. - - Raises ``ValueError`` if rcode is < 0 or > 4095. - - Returns a ``str``. + :param value: The rcode. + :type value: :py:class:`dns.rcode.Rcode` + :raises ValueError: If the rcode is < 0 or > 4095. + :rtype: str """ if tsig and value == Rcode.BADVERS: diff --git a/dns/rdata.py b/dns/rdata.py index ecce77a4..2d89c005 100644 --- a/dns/rdata.py +++ b/dns/rdata.py @@ -65,29 +65,39 @@ class RdataStyle(dns.name.NameStyle): An ``RdataStyle`` is also a :py:class:`dns.name.NameStyle`; see that class for a description of its options. - If *txt_is_utf8* is ``True``, then TXT-like records will be treated - as UTF-8 if they decode successfully, and the output string may contain any - Unicode codepoint. If ``False``, the default, then TXT-like records are - treated according to RFC 1035 rules. + .. attribute:: txt_is_utf8 - *base64_chunk_size*, an ``int`` with default 32, specifies the chunk size for - text representations that break base64 strings into chunks. + A ``bool``. If ``True``, TXT-like records will be treated as UTF-8 if + they decode successfully, and the output string may contain any Unicode + codepoint. If ``False`` (the default), TXT-like records are treated + according to RFC 1035 rules. - *base64_chunk_separator*, a ``str`` with default ``" "``, specifies the - chunk separator for text representations that break base64 strings into chunks. + .. attribute:: base64_chunk_size - *hex_chunk_size*, an ``int`` with default 128, specifies the chunk size for - text representations that break hex strings into chunks. + An ``int`` (default 32). The chunk size for text representations that + break base64 strings into chunks. - *hex_chunk_separator*, a ``str`` with default ``" "``, specifies the - chunk separator for text representations that break hex strings into chunks. + .. attribute:: base64_chunk_separator - *truncate_crypto*, a ``bool``. The default is ``False``. If ``True``, then - output of crypto types (e.g. DNSKEY) is altered to be readable - by humans in a debugging context, but the crypto content will be removed. - A sample use would be a "dig" application where you wanted to see how many - DNSKEYs there were, and what key ids they had, without seeing the actual - public key data. Use of this option will lose information. + A ``str`` (default ``" "``). The separator for text representations + that break base64 strings into chunks. + + .. attribute:: hex_chunk_size + + An ``int`` (default 128). The chunk size for text representations that + break hex strings into chunks. + + .. attribute:: hex_chunk_separator + + A ``str`` (default ``" "``). The separator for text representations + that break hex strings into chunks. + + .. attribute:: truncate_crypto + + A ``bool`` (default ``False``). If ``True``, output of crypto types + (e.g. DNSKEY) is altered to be human-readable in a debugging context, + but the crypto content is removed. Use of this option will lose + information. """ txt_is_utf8: bool = False @@ -236,9 +246,10 @@ class Rdata: ) -> None: """Initialize an rdata. - *rdclass*, an ``int`` is the rdataclass of the Rdata. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. + :param rdclass: The rdata class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param rdtype: The rdata type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` """ self.rdclass = self._as_rdataclass(rdclass) @@ -281,7 +292,7 @@ class Rdata: creating rdatasets, allowing the rdataset to contain only RRSIGs of a particular type, e.g. RRSIG(NS). - Returns a ``dns.rdatatype.RdataType``. + :rtype: :py:class:`dns.rdatatype.RdataType` """ return dns.rdatatype.NONE @@ -291,7 +302,7 @@ class Rdata: which are the ordinary DNS type, and the upper 16 bits of which are the "covered" type, if any. - Returns an ``int``. + :rtype: int """ return self.covers() << 16 | self.rdtype @@ -305,10 +316,9 @@ class Rdata: ) -> str: """Convert an rdata to text format. - *style*, a :py:class:`dns.rdata.RdataStyle` or ``None`` (the default). If - specified, the style overrides the other parameters. - - Returns a ``str``. + :param style: If specified, overrides *origin* and *relativize*. + :type style: :py:class:`dns.rdata.RdataStyle` or ``None`` + :rtype: str """ if style is None: kw = kw.copy() @@ -323,7 +333,7 @@ class Rdata: See the documentation for :py:class:`dns.rdata.RdataStyle` for a description of the style parameters. - Returns a ``str``. + :rtype: str """ raise NotImplementedError # pragma: no cover @@ -346,7 +356,9 @@ class Rdata: ) -> bytes | None: """Convert an rdata to wire format. - Returns a ``bytes`` if no output file was specified, or ``None`` otherwise. + :returns: Wire-format bytes if no output file was specified, or ``None`` + if a file was provided. + :rtype: bytes or ``None`` """ if file: @@ -362,9 +374,9 @@ class Rdata: return f.getvalue() def to_generic(self, origin: dns.name.Name | None = None) -> "GenericRdata": - """Creates a dns.rdata.GenericRdata equivalent of this rdata. + """Create a :py:class:`dns.rdata.GenericRdata` equivalent of this rdata. - Returns a ``dns.rdata.GenericRdata``. + :rtype: :py:class:`dns.rdata.GenericRdata` """ wire = self.to_wire(origin=origin) assert wire is not None # for type checkers @@ -374,7 +386,7 @@ class Rdata: """Convert rdata to a format suitable for digesting in hashes. This is also the DNSSEC canonical form. - Returns a ``bytes``. + :rtype: bytes """ wire = self.to_wire(origin=origin, canonicalize=True) assert wire is not None # for mypy @@ -540,15 +552,15 @@ class Rdata: raise NotImplementedError # pragma: no cover def replace(self, **kwargs: Any) -> "Rdata": - """ - Create a new Rdata instance based on the instance replace was + """Create a new Rdata instance based on the instance replace was invoked on. It is possible to pass different parameters to override the corresponding properties of the base Rdata. Any field specific to the Rdata type can be replaced, but the *rdtype* and *rdclass* fields cannot. - Returns an instance of the same Rdata subclass as *self*. + :returns: A new instance of the same :py:class:`Rdata` subclass as *self*. + :rtype: :py:class:`Rdata` """ # Get the constructor parameters. @@ -816,9 +828,11 @@ def load_all_types(disable_dynamic_load=True): Normally dnspython loads DNS rdatatype implementations on demand, but in some specialized cases loading all types at an application-controlled time is preferred. - If *disable_dynamic_load*, a ``bool``, is ``True`` then dnspython will not attempt - to use its dynamic loading mechanism if an unknown type is subsequently encountered, - and will simply use the ``GenericRdata`` class. + :param disable_dynamic_load: If ``True`` (the default), dnspython will not + attempt to use its dynamic loading mechanism if an unknown type is + subsequently encountered, and will simply use the ``GenericRdata`` + class. + :type disable_dynamic_load: bool """ # Load class IN and ANY types. for rdtype in dns.rdatatype.RdataType: @@ -856,27 +870,23 @@ def from_text( If *tok* is a ``str``, then a tokenizer is created and the string is used as its input. - *rdclass*, a ``dns.rdataclass.RdataClass`` or ``str``, the rdataclass. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdatatype. - - *tok*, a ``dns.tokenizer.Tokenizer`` or a ``str``. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use if a tokenizer needs to be created. If - ``None``, the default IDNA 2003 encoder/decoder is used. If a - tokenizer is not created, then the codec associated with the tokenizer - is the one that is used. - - Returns an instance of the chosen Rdata subclass. + :param rdclass: The rdata class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or ``str`` + :param rdtype: The rdata type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param tok: The tokenizer or input string. + :type tok: :py:class:`dns.tokenizer.Tokenizer` or ``str`` + :param origin: The origin to use for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param relativize: If ``True``, names will be relativized. Default is ``True``. + :type relativize: bool + :param relativize_to: The origin to use when relativizing. Defaults to *origin*. + :type relativize_to: :py:class:`dns.name.Name` or ``None`` + :param idna_codec: The IDNA encoder/decoder to use when creating a tokenizer. + If ``None``, the default IDNA 2003 codec is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :returns: An instance of the chosen :py:class:`Rdata` subclass. + :rtype: :py:class:`Rdata` """ if isinstance(tok, str): @@ -943,17 +953,16 @@ def from_wire_parser( Once a class is chosen, its from_wire() class method is called with the parameters to this function. - *rdclass*, a ``dns.rdataclass.RdataClass`` or ``str``, the rdataclass. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdatatype. - - *parser*, a ``dns.wire.Parser``, the parser, which should be - restricted to the rdata length. - - *origin*, a ``dns.name.Name`` (or ``None``). If not ``None``, - then names will be relativized to this origin. - - Returns an instance of the chosen Rdata subclass. + :param rdclass: The rdata class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or ``str`` + :param rdtype: The rdata type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param parser: The wire format parser, restricted to the rdata length. + :type parser: :py:class:`dns.wire.Parser` + :param origin: If not ``None``, names will be relativized to this origin. + :type origin: :py:class:`dns.name.Name` or ``None`` + :returns: An instance of the chosen :py:class:`Rdata` subclass. + :rtype: :py:class:`Rdata` """ rdclass = dns.rdataclass.RdataClass.make(rdclass) @@ -982,21 +991,20 @@ def from_wire( Once a class is chosen, its from_wire() class method is called with the parameters to this function. - *rdclass*, an ``int``, the rdataclass. - - *rdtype*, an ``int``, the rdatatype. - - *wire*, a ``bytes``, the wire-format message. - - *current*, an ``int``, the offset in wire of the beginning of - the rdata. - - *rdlen*, an ``int``, the length of the wire-format rdata - - *origin*, a ``dns.name.Name`` (or ``None``). If not ``None``, - then names will be relativized to this origin. - - Returns an instance of the chosen Rdata subclass. + :param rdclass: The rdata class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or ``str`` + :param rdtype: The rdata type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or ``str`` + :param wire: The wire-format message. + :type wire: bytes + :param current: The offset of the start of the rdata in *wire*. + :type current: int + :param rdlen: The length of the rdata in wire format. + :type rdlen: int + :param origin: If not ``None``, names will be relativized to this origin. + :type origin: :py:class:`dns.name.Name` or ``None`` + :returns: An instance of the chosen :py:class:`Rdata` subclass. + :rtype: :py:class:`Rdata` """ parser = dns.wire.Parser(wire, current) with parser.restrict_to(rdlen): @@ -1022,18 +1030,16 @@ def register_type( ) -> None: """Dynamically register a module to handle an rdatatype. - *implementation*, a subclass of ``dns.rdata.Rdata`` implementing the type, - or a module containing such a class named by its text form. - - *rdtype*, an ``int``, the rdatatype to register. - - *rdtype_text*, a ``str``, the textual form of the rdatatype. - - *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e. - RRsets of the type can have only one member.) - - *rdclass*, the rdataclass of the type, or ``dns.rdataclass.ANY`` if - it applies to all classes. + :param implementation: A subclass of :py:class:`dns.rdata.Rdata` implementing + the type, or a module containing such a class named by its text form. + :param rdtype: The rdatatype to register. + :type rdtype: int + :param rdtype_text: The textual form of the rdatatype. + :type rdtype_text: str + :param is_singleton: If ``True``, RRsets of this type can have only one member. + :type is_singleton: bool + :param rdclass: The rdata class, or ``dns.rdataclass.ANY`` for all classes. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` """ rdtype = dns.rdatatype.RdataType.make(rdtype) diff --git a/dns/rdataclass.py b/dns/rdataclass.py index 89b85a79..cc5348e5 100644 --- a/dns/rdataclass.py +++ b/dns/rdataclass.py @@ -66,11 +66,9 @@ def from_text(text: str) -> RdataClass: For example, "IN" and "CLASS1" will both result in a value of 1. - Raises ``dns.rdatatype.UnknownRdataclass`` if the class is unknown. - - Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535. - - Returns a ``dns.rdataclass.RdataClass``. + :raises dns.rdataclass.UnknownRdataclass: If the class is unknown. + :raises ValueError: If the rdata class value is not >= 0 and <= 65535. + :rtype: :py:class:`dns.rdataclass.RdataClass` """ return RdataClass.from_text(text) @@ -82,9 +80,8 @@ def to_text(value: RdataClass) -> str: If the value has a known mnemonic, it will be used, otherwise the DNS generic class syntax will be used. - Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535. - - Returns a ``str``. + :raises ValueError: If the rdata class value is not >= 0 and <= 65535. + :rtype: str """ return RdataClass.to_text(value) @@ -95,7 +92,8 @@ def is_metaclass(rdclass: RdataClass) -> bool: The currently defined metaclasses are ANY and NONE. - *rdclass* is a ``dns.rdataclass.RdataClass``. + :param rdclass: The rdata class to check. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` """ if rdclass in _metaclasses: diff --git a/dns/rdataset.py b/dns/rdataset.py index 3d5c3372..01e4743c 100644 --- a/dns/rdataset.py +++ b/dns/rdataset.py @@ -55,51 +55,75 @@ class RdatasetStyle(dns.rdata.RdataStyle): :py:class:`dns.rdata.RdataStyle`. See those classes for a description of their options. - *override_rdclass*, a ``dns.rdataclass.RdataClass`` or ``None``. - If not ``None``, use this class instead of the Rdataset's class. + .. attribute:: override_rdclass - *want_comments*, a ``bool``. If ``True``, emit comments for rdata - which have them. The default is ``False``. + A :py:class:`dns.rdataclass.RdataClass` or ``None``. If not ``None``, + use this class instead of the Rdataset's class. - *omit_rdclass*, a ``bool``. If ``True``, do not print the RdataClass. - The default is ``False``. + .. attribute:: want_comments - *omit_ttl*, a ``bool``. If ``True``, do not print the TTL. - The default is ``False``. Use of this option may lose information. + A ``bool``. If ``True``, emit comments for rdata which have them. + The default is ``False``. - *want_generic*, a ``bool``. If ``True``, print RdataClass, RdataType, - and Rdatas in the generic format, a.k.a. the "unknown rdata format". - The default is ``False``. + .. attribute:: omit_rdclass - *deduplicate_names*, a ``bool``. If ``True``, print whitespace instead of the - owner name if the owner name of an RR is the same as the prior RR's owner name. - The default is ``False``. + A ``bool``. If ``True``, do not print the RdataClass. The default is + ``False``. - *first_name_is_duplicate*, a ``bool``. If ``True``, consider the first owner name - of the rdataset as a duplicate too, and emit whitespace for it as well. A sample - use is in emitting a Node of multiple rdatasets and the current rdataset is not - the first to be emitted. The default is ``False``. + .. attribute:: omit_ttl - *default_ttl*, an ``int`` or ``None``. If ``None``, the default, there is no - default TTL. If an integer is specified, then any TTL matching that value will - be omitted. When emitting a zonefile, a setting other than ``None`` will cause - a ``$TTL`` directive to be emitted. + A ``bool``. If ``True``, do not print the TTL. The default is + ``False``. Use of this option may lose information. - *name_just*, an ``int``. The owner name field justification. Negative values - are left justified, and positive values are right justified. A value of zero, - the default, means that no justification is performed. + .. attribute:: want_generic - *ttl_just*, an ``int``. The TTL field justification. Negative values - are left justified, and positive values are right justified. A value of zero, - the default, means that no justification is performed. + A ``bool``. If ``True``, print RdataClass, RdataType, and Rdatas in + the generic format (the "unknown rdata format"). The default is + ``False``. - *rdclass_just*, an ``int``. The RdataClass name field justification. Negative values - are left justified, and positive values are right justified. A value of zero, - the default, means that no justification is performed. + .. attribute:: deduplicate_names - *rdtype_just*, an ``int``. The RdataType field justification. Negative values - are left justified, and positive values are right justified. A value of zero, - the default, means that no justification is performed. + A ``bool``. If ``True``, print whitespace instead of the owner name + when the owner name of an RR is the same as the prior RR's owner name. + The default is ``False``. + + .. attribute:: first_name_is_duplicate + + A ``bool``. If ``True``, consider the first owner name of the rdataset + as a duplicate too, emitting whitespace for it as well. Useful when + emitting a Node of multiple rdatasets and the current rdataset is not + the first. The default is ``False``. + + .. attribute:: default_ttl + + An ``int`` or ``None``. If ``None`` (the default), there is no default + TTL. If an integer is specified, any TTL matching that value will be + omitted. When emitting a zonefile, a value other than ``None`` will + cause a ``$TTL`` directive to be emitted. + + .. attribute:: name_just + + An ``int``. The owner name field justification. Negative values are + left-justified, positive values are right-justified. Zero (the default) + means no justification. + + .. attribute:: ttl_just + + An ``int``. The TTL field justification. Negative values are + left-justified, positive values are right-justified. Zero (the default) + means no justification. + + .. attribute:: rdclass_just + + An ``int``. The RdataClass field justification. Negative values are + left-justified, positive values are right-justified. Zero (the default) + means no justification. + + .. attribute:: rdtype_just + + An ``int``. The RdataType field justification. Negative values are + left-justified, positive values are right-justified. Zero (the default) + means no justification. """ override_rdclass: dns.rdataclass.RdataClass | None = None @@ -139,13 +163,14 @@ class Rdataset(dns.set.Set): ): """Create a new rdataset of the specified class and type. - *rdclass*, a ``dns.rdataclass.RdataClass``, the rdataclass. - - *rdtype*, an ``dns.rdatatype.RdataType``, the rdatatype. - - *covers*, an ``dns.rdatatype.RdataType``, the covered rdatatype. - - *ttl*, an ``int``, the TTL. + :param rdclass: The rdataclass. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param rdtype: The rdatatype. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :param covers: The covered rdatatype. + :type covers: :py:class:`dns.rdatatype.RdataType` + :param ttl: The TTL. + :type ttl: int """ super().__init__() @@ -169,7 +194,8 @@ class Rdataset(dns.set.Set): TTL or the specified TTL. If the set contains no rdatas, set the TTL to the specified TTL. - *ttl*, an ``int`` or ``str``. + :param ttl: The candidate TTL value. + :type ttl: int or str """ ttl = dns.ttl.make(ttl) if len(self) == 0: @@ -184,15 +210,14 @@ class Rdataset(dns.set.Set): If the optional *ttl* parameter is supplied, then ``self.update_ttl(ttl)`` will be called prior to adding the rdata. - *rd*, a ``dns.rdata.Rdata``, the rdata - - *ttl*, an ``int``, the TTL. - - Raises ``dns.rdataset.IncompatibleTypes`` if the type and class - do not match the type and class of the rdataset. - - Raises ``dns.rdataset.DifferingCovers`` if the type is a signature - type and the covered type does not match that of the rdataset. + :param rd: The rdata to add. + :type rd: :py:class:`dns.rdata.Rdata` + :param ttl: The TTL. + :type ttl: int or ``None`` + :raises dns.rdataset.IncompatibleTypes: If the type and class do not + match the type and class of the rdataset. + :raises dns.rdataset.DifferingCovers: If the type is a signature type + and the covered type does not match that of the rdataset. """ # @@ -226,8 +251,8 @@ class Rdataset(dns.set.Set): def update(self, other): """Add all rdatas in other to self. - *other*, a ``dns.rdataset.Rdataset``, the rdataset from which - to update. + :param other: The rdataset from which to update. + :type other: :py:class:`dns.rdataset.Rdataset` """ self.update_ttl(other.ttl) @@ -293,23 +318,21 @@ class Rdataset(dns.set.Set): Any additional keyword arguments are passed on to the rdata ``to_text()`` method. - *name*, a ``dns.name.Name``. If name is not ``None``, emit RRs with - *name* as the owner name. - - *origin*, a ``dns.name.Name`` or ``None``, the origin for relative - names. - - *relativize*, a ``bool``. If ``True``, names will be relativized - to *origin*. - - *override_rdclass*, a ``dns.rdataclass.RdataClass`` or ``None``. - If not ``None``, when rendering, emit records as if they were of this class. - - *want_comments*, a ``bool``. If ``True``, emit comments for rdata - which have them. The default is ``False``. - - *style*, a :py:class:`dns.rdataset.RdatasetStyle` or ``None`` (the default). If - specified, the style overrides the other parameters except for *name*. + :param name: If not ``None``, emit RRs with this as the owner name. + :type name: :py:class:`dns.name.Name` or ``None`` + :param origin: The origin for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param relativize: If ``True``, names will be relativized to *origin*. + :type relativize: bool + :param override_rdclass: If not ``None``, emit records as if they were + of this class. + :type override_rdclass: :py:class:`dns.rdataclass.RdataClass` or ``None`` + :param want_comments: If ``True``, emit comments for rdata which have + them. The default is ``False``. + :type want_comments: bool + :param style: If specified, overrides the other parameters except + *name*. + :type style: :py:class:`dns.rdataset.RdatasetStyle` or ``None`` """ if style is None: kw = kw.copy() @@ -400,26 +423,25 @@ class Rdataset(dns.set.Set): ) -> int: """Convert the rdataset to wire format. - *name*, a ``dns.name.Name`` is the owner name to use. - - *file* is the file where the name is emitted (typically a - BytesIO file). - - *compress*, a ``dict``, is the compression table to use. If - ``None`` (the default), names will not be compressed. - - *origin* is a ``dns.name.Name`` or ``None``. If the name is - relative and origin is not ``None``, then *origin* will be appended - to it. - - *override_rdclass*, an ``int``, is used as the class instead of the - class of the rdataset. This is useful when rendering rdatasets - associated with dynamic updates. - - *want_shuffle*, a ``bool``. If ``True``, then the order of the - Rdatas within the Rdataset will be shuffled before rendering. - - Returns an ``int``, the number of records emitted. + :param name: The owner name to use. + :type name: :py:class:`dns.name.Name` + :param file: The file where the name is emitted (typically a + ``BytesIO`` file). + :param compress: The compression table to use. If ``None`` (the + default), names will not be compressed. + :type compress: dict or ``None`` + :param origin: If the name is relative and *origin* is not ``None``, + *origin* will be appended to it. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param override_rdclass: If not ``None``, used as the class instead of + the class of the rdataset. Useful for dynamic update rendering. + :type override_rdclass: int or ``None`` + :param want_shuffle: If ``True``, the order of Rdatas within the + Rdataset will be shuffled before rendering. + :type want_shuffle: bool + + :returns: The number of records emitted. + :rtype: int """ if override_rdclass is not None: @@ -556,19 +578,18 @@ def from_text_list( """Create an rdataset with the specified class, type, and TTL, and with the specified list of rdatas in text format. - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use; if ``None``, the default IDNA 2003 - encoder/decoder is used. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - Returns a ``dns.rdataset.Rdataset`` object. + :param idna_codec: Specifies the IDNA encoder/decoder. If ``None``, the + default IDNA 2003 encoder/decoder is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param origin: The origin to use for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param relativize: If ``True``, names will be relativized. + :type relativize: bool + :param relativize_to: The origin to use when relativizing names. If not + set, *origin* is used. + :type relativize_to: :py:class:`dns.name.Name` or ``None`` + + :rtype: :py:class:`dns.rdataset.Rdataset` """ rdclass = dns.rdataclass.RdataClass.make(rdclass) @@ -592,7 +613,7 @@ def from_text( """Create an rdataset with the specified class, type, and TTL, and with the specified rdatas in text format. - Returns a ``dns.rdataset.Rdataset`` object. + :rtype: :py:class:`dns.rdataset.Rdataset` """ return from_text_list(rdclass, rdtype, ttl, cast(Collection[str], text_rdatas)) @@ -602,7 +623,7 @@ def from_rdata_list(ttl: int, rdatas: Collection[dns.rdata.Rdata]) -> Rdataset: """Create an rdataset with the specified TTL, and with the specified list of rdata objects. - Returns a ``dns.rdataset.Rdataset`` object. + :rtype: :py:class:`dns.rdataset.Rdataset` """ if len(rdatas) == 0: @@ -621,7 +642,7 @@ def from_rdata(ttl: int, *rdatas: Any) -> Rdataset: """Create an rdataset with the specified TTL, and with the specified rdata objects. - Returns a ``dns.rdataset.Rdataset`` object. + :rtype: :py:class:`dns.rdataset.Rdataset` """ return from_rdata_list(ttl, cast(Collection[dns.rdata.Rdata], rdatas)) diff --git a/dns/rdatatype.py b/dns/rdatatype.py index 2462f7ad..1e7cdb63 100644 --- a/dns/rdatatype.py +++ b/dns/rdatatype.py @@ -172,11 +172,9 @@ def from_text(text: str) -> RdataType: For example, "NS" and "TYPE2" will both result in a value of 2. - Raises ``dns.rdatatype.UnknownRdatatype`` if the type is unknown. - - Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535. - - Returns a ``dns.rdatatype.RdataType``. + :raises dns.rdatatype.UnknownRdatatype: If the type is unknown. + :raises ValueError: If the rdata type value is not >= 0 and <= 65535. + :rtype: :py:class:`dns.rdatatype.RdataType` """ return RdataType.from_text(text) @@ -188,9 +186,8 @@ def to_text(value: RdataType) -> str: If the value has a known mnemonic, it will be used, otherwise the DNS generic type syntax will be used. - Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535. - - Returns a ``str``. + :raises ValueError: If the rdata type value is not >= 0 and <= 65535. + :rtype: str """ return RdataType.to_text(value) @@ -199,12 +196,12 @@ def to_text(value: RdataType) -> str: def is_metatype(rdtype: RdataType) -> bool: """True if the specified type is a metatype. - *rdtype* is a ``dns.rdatatype.RdataType``. - The currently defined metatypes are TKEY, TSIG, IXFR, AXFR, MAILA, MAILB, ANY, OPT, and NXNAME. - Returns a ``bool``. + :param rdtype: The rdata type to check. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :rtype: bool """ return (256 > rdtype >= 128) or rdtype in _metatypes @@ -219,9 +216,9 @@ def is_singleton(rdtype: RdataType) -> bool: The currently defined singleton types are CNAME, DNAME, NSEC, NXT, and SOA. - *rdtype* is an ``int``. - - Returns a ``bool``. + :param rdtype: The rdata type to check. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :rtype: bool """ if rdtype in _singletons: @@ -235,12 +232,13 @@ def register_type( ) -> None: """Dynamically register an rdatatype. - *rdtype*, a ``dns.rdatatype.RdataType``, the rdatatype to register. - - *rdtype_text*, a ``str``, the textual form of the rdatatype. - - *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e. - RRsets of the type can have only one member.) + :param rdtype: The rdatatype to register. + :type rdtype: :py:class:`dns.rdatatype.RdataType` + :param rdtype_text: The textual form of the rdatatype. + :type rdtype_text: str + :param is_singleton: If ``True``, RRsets of this type can have only one + member. + :type is_singleton: bool """ _registered_by_text[rdtype_text] = rdtype diff --git a/dns/rdtypes/ANY/OPT.py b/dns/rdtypes/ANY/OPT.py index 57b754ee..3f7733b8 100644 --- a/dns/rdtypes/ANY/OPT.py +++ b/dns/rdtypes/ANY/OPT.py @@ -35,12 +35,13 @@ class OPT(dns.rdata.Rdata): def __init__(self, rdclass, rdtype, options): """Initialize an OPT rdata. - *rdclass*, an ``int`` is the rdataclass of the Rdata, - which is also the payload size. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. - - *options*, a tuple of ``bytes`` + :param rdclass: The rdataclass of the Rdata, which is also the + payload size. + :type rdclass: int + :param rdtype: The rdatatype of the Rdata. + :type rdtype: int + :param options: The EDNS options. + :type options: tuple of :py:class:`dns.edns.Option` """ super().__init__(rdclass, rdtype) diff --git a/dns/rdtypes/ANY/TSIG.py b/dns/rdtypes/ANY/TSIG.py index a848e19d..5c01c746 100644 --- a/dns/rdtypes/ANY/TSIG.py +++ b/dns/rdtypes/ANY/TSIG.py @@ -52,23 +52,24 @@ class TSIG(dns.rdata.Rdata): ): """Initialize a TSIG rdata. - *rdclass*, an ``int`` is the rdataclass of the Rdata. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. - - *algorithm*, a ``dns.name.Name``. - - *time_signed*, an ``int``. - - *fudge*, an ``int`. - - *mac*, a ``bytes`` - - *original_id*, an ``int`` - - *error*, an ``int`` - - *other*, a ``bytes`` + :param rdclass: The rdataclass of the Rdata. + :type rdclass: int + :param rdtype: The rdatatype of the Rdata. + :type rdtype: int + :param algorithm: The TSIG algorithm name. + :type algorithm: :py:class:`dns.name.Name` + :param time_signed: The time signed (seconds since epoch). + :type time_signed: int + :param fudge: The fudge (seconds of error permitted in time_signed). + :type fudge: int + :param mac: The message authentication code. + :type mac: bytes + :param original_id: The original message ID. + :type original_id: int + :param error: The TSIG error code. + :type error: int + :param other: Other data (typically empty). + :type other: bytes """ super().__init__(rdclass, rdtype) diff --git a/dns/rdtypes/dnskeybase.py b/dns/rdtypes/dnskeybase.py index 243415b0..59d979bc 100644 --- a/dns/rdtypes/dnskeybase.py +++ b/dns/rdtypes/dnskeybase.py @@ -91,9 +91,7 @@ class DNSKEYBase(dns.rdata.Rdata): def key_id(self) -> int: """Return the key id (a 16-bit number) for the specified key. - *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` - - Returns an ``int`` between 0 and 65535 + :rtype: int """ wire = self.to_wire() diff --git a/dns/rdtypes/txtbase.py b/dns/rdtypes/txtbase.py index 8722c34c..f6b9fe75 100644 --- a/dns/rdtypes/txtbase.py +++ b/dns/rdtypes/txtbase.py @@ -46,11 +46,12 @@ class TXTBase(dns.rdata.Rdata): ): """Initialize a TXT-like rdata. - *rdclass*, an ``int`` is the rdataclass of the Rdata. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. - - *strings*, a tuple of ``bytes`` + :param rdclass: The rdataclass of the Rdata. + :type rdclass: int + :param rdtype: The rdatatype of the Rdata. + :type rdtype: int + :param strings: The strings. + :type strings: tuple of bytes """ super().__init__(rdclass, rdtype) self.strings: tuple[bytes] = self._as_tuple( diff --git a/dns/resolver.py b/dns/resolver.py index 849d67e6..ba0b789d 100644 --- a/dns/resolver.py +++ b/dns/resolver.py @@ -120,22 +120,23 @@ class NXDOMAIN(dns.exception.DNSException): def qnames(self): """All of the names that were tried. - Returns a list of ``dns.name.Name``. + :rtype: list[:py:class:`dns.name.Name`] """ return self.kwargs["qnames"] def responses(self): """A map from queried names to their NXDOMAIN responses. - Returns a dict mapping a ``dns.name.Name`` to a - ``dns.message.Message``. + :rtype: dict[:py:class:`dns.name.Name`, :py:class:`dns.message.Message`] """ return self.kwargs["responses"] def response(self, qname): """The response for query *qname*. - Returns a ``dns.message.Message``. + :param qname: The query name. + :type qname: :py:class:`dns.name.Name` + :rtype: :py:class:`dns.message.Message` """ return self.kwargs["responses"][qname] @@ -427,8 +428,10 @@ class Cache(CacheBase): """Simple thread-safe DNS answer cache.""" def __init__(self, cleaning_interval: float = 300.0) -> None: - """*cleaning_interval*, a ``float`` is the number of seconds between - periodic cleanings. + """Initialize the cache. + + :param cleaning_interval: Seconds between periodic cache cleanings. + :type cleaning_interval: float """ super().__init__() @@ -451,14 +454,12 @@ class Cache(CacheBase): self.next_cleaning = now + self.cleaning_interval def get(self, key: CacheKey) -> Answer | None: - """Get the answer associated with *key*. - - Returns None if no answer is cached for the key. + """Get the answer associated with *key*, or ``None`` if not cached. - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - - Returns a ``dns.resolver.Answer`` or ``None``. + :param key: A (name, rdtype, rdclass) tuple identifying the query. + :type key: tuple[:py:class:`dns.name.Name`, :py:class:`dns.rdatatype.RdataType`, :py:class:`dns.rdataclass.RdataClass`] + :returns: The cached answer, or ``None`` if not found or expired. + :rtype: :py:class:`dns.resolver.Answer` or ``None`` """ with self.lock: @@ -471,12 +472,11 @@ class Cache(CacheBase): return v def put(self, key: CacheKey, value: Answer) -> None: - """Associate key and value in the cache. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. + """Associate *key* with *value* in the cache. - *value*, a ``dns.resolver.Answer``, the answer. + :param key: A (name, rdtype, rdclass) tuple identifying the query. + :param value: The answer to cache. + :type value: :py:class:`dns.resolver.Answer` """ with self.lock: @@ -486,11 +486,8 @@ class Cache(CacheBase): def flush(self, key: CacheKey | None = None) -> None: """Flush the cache. - If *key* is not ``None``, only that item is flushed. Otherwise the entire cache - is flushed. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. + :param key: If not ``None``, flush only this entry; otherwise flush + the entire cache. """ with self.lock: @@ -534,8 +531,11 @@ class LRUCache(CacheBase): """ def __init__(self, max_size: int = 100000) -> None: - """*max_size*, an ``int``, is the maximum number of nodes to cache; - it must be greater than 0. + """Initialize an LRU cache. + + :param max_size: The maximum number of nodes to cache; must be greater + than 0. + :type max_size: int """ super().__init__() @@ -553,12 +553,13 @@ class LRUCache(CacheBase): def get(self, key: CacheKey) -> Answer | None: """Get the answer associated with *key*. - Returns None if no answer is cached for the key. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. + Returns ``None`` if no answer is cached for the key. - Returns a ``dns.resolver.Answer`` or ``None``. + :param key: A ``(dns.name.Name, dns.rdatatype.RdataType, + dns.rdataclass.RdataClass)`` tuple whose values are the query + name, rdtype, and rdclass respectively. + :type key: tuple + :rtype: :py:class:`dns.resolver.Answer` or ``None`` """ with self.lock: @@ -590,10 +591,12 @@ class LRUCache(CacheBase): def put(self, key: CacheKey, value: Answer) -> None: """Associate key and value in the cache. - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - - *value*, a ``dns.resolver.Answer``, the answer. + :param key: A ``(dns.name.Name, dns.rdatatype.RdataType, + dns.rdataclass.RdataClass)`` tuple whose values are the query + name, rdtype, and rdclass respectively. + :type key: tuple + :param value: The answer to cache. + :type value: :py:class:`dns.resolver.Answer` """ with self.lock: @@ -612,11 +615,10 @@ class LRUCache(CacheBase): def flush(self, key: CacheKey | None = None) -> None: """Flush the cache. - If *key* is not ``None``, only that item is flushed. Otherwise the entire cache - is flushed. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. + :param key: If not ``None``, flush only this entry; otherwise flush + the entire cache. The key is a ``(dns.name.Name, + dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` tuple. + :type key: tuple or ``None`` """ with self.lock: @@ -688,8 +690,8 @@ class _Resolution: ) -> tuple[dns.message.QueryMessage | None, Answer | None]: """Get the next request to send, and check the cache. - Returns a (request, answer) tuple. At most one of request or - answer will not be None. + :returns: A (request, answer) tuple; at most one element is not ``None``. + :rtype: tuple[:py:class:`dns.message.QueryMessage` or ``None``, :py:class:`dns.resolver.Answer` or ``None``] """ # We return a tuple instead of Union[Message,Answer] as it lets @@ -935,15 +937,16 @@ class BaseResolver: def __init__( self, filename: str = "/etc/resolv.conf", configure: bool = True ) -> None: - """*filename*, a ``str`` or file object, specifying a file - in standard /etc/resolv.conf format. This parameter is meaningful - only when *configure* is true and the platform is POSIX. - - *configure*, a ``bool``. If True (the default), the resolver - instance is configured in the normal fashion for the operating - system the resolver is running on. (I.e. by reading a - /etc/resolv.conf file on POSIX systems and from the registry - on Windows systems.) + """Initialize a resolver. + + :param filename: A ``str`` or file object specifying a file in + standard ``/etc/resolv.conf`` format. Meaningful only when + *configure* is ``True`` and the platform is POSIX. + :type filename: str or file + :param configure: If ``True`` (the default), configure the resolver + for the operating system (reads ``/etc/resolv.conf`` on POSIX, + registry on Windows). + :type configure: bool """ self.reset() @@ -1152,19 +1155,17 @@ class BaseResolver: ) -> None: """Configure EDNS behavior. - *edns*, an ``int``, is the EDNS level to use. Specifying - ``None``, ``False``, or ``-1`` means "do not use EDNS", and in this case - the other parameters are ignored. Specifying ``True`` is - equivalent to specifying 0, i.e. "use EDNS0". - - *ednsflags*, an ``int``, the EDNS flag values. - - *payload*, an ``int``, is the EDNS sender's payload field, which is the - maximum size of UDP datagram the sender can handle. I.e. how big - a response to this message can be. - - *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS - options. + :param edns: The EDNS level to use. ``None``, ``False``, or ``-1`` + means do not use EDNS (other parameters are ignored). ``True`` + is equivalent to ``0`` (EDNS0). + :type edns: int or bool or ``None`` + :param ednsflags: The EDNS flag values. + :type ednsflags: int + :param payload: The EDNS sender's payload field — the maximum UDP + datagram size the sender can handle. + :type payload: int + :param options: EDNS options, or ``None``. + :type options: list[:py:class:`dns.edns.Option`] or ``None`` """ if edns is None or edns is False: @@ -1177,9 +1178,10 @@ class BaseResolver: self.ednsoptions = options def set_flags(self, flags: int) -> None: - """Overrides the default flags with your own. + """Override the default query flags. - *flags*, an ``int``, the message flags to use. + :param flags: The message flags to use. + :type flags: int """ self.flags = flags @@ -1230,12 +1232,13 @@ class BaseResolver: def nameservers( self, nameservers: Sequence[str | dns.nameserver.Nameserver] ) -> None: - """ - *nameservers*, a ``list`` or ``tuple`` of nameservers, where a nameserver is either - a string interpretable as a nameserver, or a ``dns.nameserver.Nameserver`` - instance. + """Set the resolver's nameservers. - Raises ``ValueError`` if *nameservers* is not a list of nameservers. + :param nameservers: A list or tuple of nameservers, where each entry + is either a string (IP address or HTTPS URL) or a + :py:class:`dns.nameserver.Nameserver` instance. + :type nameservers: list or tuple + :raises ValueError: If *nameservers* is not a valid list of nameservers. """ # We just call _enrich_nameservers() for checking self._enrich_nameservers(nameservers, self.nameserver_ports, self.port) @@ -1259,53 +1262,40 @@ class Resolver(BaseResolver): ) -> Answer: # pylint: disable=arguments-differ """Query nameservers to find the answer to the question. - The *qname*, *rdtype*, and *rdclass* parameters may be objects - of the appropriate type, or strings that can be converted into objects - of the appropriate type. - - *qname*, a ``dns.name.Name`` or ``str``, the query name. - - *rdtype*, an ``int`` or ``str``, the query type. - - *rdclass*, an ``int`` or ``str``, the query class. - - *tcp*, a ``bool``. If ``True``, use TCP to make the query. - - *source*, a ``str`` or ``None``. If not ``None``, bind to this IP - address when making queries. - - *raise_on_no_answer*, a ``bool``. If ``True``, raise - ``dns.resolver.NoAnswer`` if there's no answer to the question. - - *source_port*, an ``int``, the port from which to send the message. - - *lifetime*, a ``float``, how many seconds a query should run - before timing out. - - *search*, a ``bool`` or ``None``, determines whether the - search list configured in the system's resolver configuration - are used for relative names, and whether the resolver's domain - may be added to relative names. The default is ``None``, - which causes the value of the resolver's - ``use_search_by_default`` attribute to be used. - - Raises ``dns.resolver.LifetimeTimeout`` if no answers could be found - in the specified lifetime. - - Raises ``dns.resolver.NXDOMAIN`` if the query name does not exist. - - Raises ``dns.resolver.YXDOMAIN`` if the query name is too long after - DNAME substitution. - - Raises ``dns.resolver.NoAnswer`` if *raise_on_no_answer* is - ``True`` and the query name exists but has no RRset of the - desired type and class. - - Raises ``dns.resolver.NoNameservers`` if no non-broken - nameservers are available to answer the question. - - Returns a ``dns.resolver.Answer`` instance. - + The *qname*, *rdtype*, and *rdclass* parameters may be objects of + the appropriate type, or strings that will be converted automatically. + + :param qname: The query name. + :type qname: :py:class:`dns.name.Name` or str + :param rdtype: The query type. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str or int + :param rdclass: The query class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` or str or int + :param tcp: If ``True``, use TCP to make the query. + :type tcp: bool + :param source: If not ``None``, bind to this IP address when making + queries. + :type source: str or ``None`` + :param raise_on_no_answer: If ``True``, raise + :py:exc:`dns.resolver.NoAnswer` if there is no answer. + :type raise_on_no_answer: bool + :param source_port: The port from which to send the message. + :type source_port: int + :param lifetime: How many seconds a query should run before timing out. + :type lifetime: float or ``None`` + :param search: Whether to use the search list for relative names. + ``None`` uses the resolver's ``use_search_by_default`` setting. + :type search: bool or ``None`` + :raises dns.resolver.LifetimeTimeout: If no answers could be found in + the specified lifetime. + :raises dns.resolver.NXDOMAIN: If the query name does not exist. + :raises dns.resolver.YXDOMAIN: If the query name is too long after + DNAME substitution. + :raises dns.resolver.NoAnswer: If *raise_on_no_answer* is ``True`` and + the query name exists but has no RRset of the desired type/class. + :raises dns.resolver.NoNameservers: If no non-broken nameservers are + available to answer the question. + :rtype: :py:class:`dns.resolver.Answer` """ resolution = _Resolution( @@ -1385,15 +1375,12 @@ class Resolver(BaseResolver): def resolve_address(self, ipaddr: str, *args: Any, **kwargs: Any) -> Answer: """Use a resolver to run a reverse query for PTR records. - This utilizes the resolve() method to perform a PTR lookup on the - specified IP address. - - *ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get - the PTR record for. + :param ipaddr: The IPv4 or IPv6 address to look up. + :type ipaddr: str - All other arguments that can be passed to the resolve() function - except for rdtype and rdclass are also supported by this - function. + All other keyword arguments accepted by + :py:meth:`~dns.resolver.Resolver.resolve` (except *rdtype* and + *rdclass*) are also supported. """ # We make a modified kwargs for type checking happiness, as otherwise # we get a legit warning about possibly having rdtype and rdclass @@ -1414,17 +1401,15 @@ class Resolver(BaseResolver): ) -> HostAnswers: """Use a resolver to query for address records. - This utilizes the resolve() method to perform A and/or AAAA lookups on - the specified name. + :param name: The name to resolve. + :type name: :py:class:`dns.name.Name` or str + :param family: The address family. ``socket.AF_UNSPEC`` (the default) + retrieves both A and AAAA records. + :type family: int - *qname*, a ``dns.name.Name`` or ``str``, the name to resolve. - - *family*, an ``int``, the address family. If socket.AF_UNSPEC - (the default), both A and AAAA records will be retrieved. - - All other arguments that can be passed to the resolve() function - except for rdtype and rdclass are also supported by this - function. + All other keyword arguments accepted by + :py:meth:`~dns.resolver.Resolver.resolve` (except *rdtype* and + *rdclass*) are also supported. """ # We make a modified kwargs for type checking happiness, as otherwise # we get a legit warning about possibly having rdtype and rdclass @@ -1479,13 +1464,13 @@ class Resolver(BaseResolver): The canonical name is the name the resolver uses for queries after all CNAME and DNAME renamings have been applied. - *name*, a ``dns.name.Name`` or ``str``, the query name. - - This method can raise any exception that ``resolve()`` can - raise, other than ``dns.resolver.NoAnswer`` and - ``dns.resolver.NXDOMAIN``. + :param name: The query name. + :type name: :py:class:`dns.name.Name` or str + :rtype: :py:class:`dns.name.Name` - Returns a ``dns.name.Name``. + This method can raise any exception that + :py:meth:`~dns.resolver.Resolver.resolve` can raise, other than + :py:exc:`dns.resolver.NoAnswer` and :py:exc:`dns.resolver.NXDOMAIN`. """ try: answer = self.resolve(name, raise_on_no_answer=False) @@ -1668,27 +1653,22 @@ def zone_for_name( ) -> dns.name.Name: # pyright: ignore """Find the name of the zone which contains the specified name. - *name*, an absolute ``dns.name.Name`` or ``str``, the query name. - - *rdclass*, an ``int``, the query class. - - *tcp*, a ``bool``. If ``True``, use TCP to make the query. - - *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use. - If ``None``, the default, then the default resolver is used. - - *lifetime*, a ``float``, the total time to allow for the queries needed - to determine the zone. If ``None``, the default, then only the individual - query limits of the resolver apply. - - Raises ``dns.resolver.NoRootSOA`` if there is no SOA RR at the DNS - root. (This is only likely to happen if you're using non-default - root servers in your network and they are misconfigured.) - - Raises ``dns.resolver.LifetimeTimeout`` if the answer could not be - found in the allotted lifetime. - - Returns a ``dns.name.Name``. + :param name: An absolute query name. + :type name: :py:class:`dns.name.Name` or str + :param rdclass: The query class. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param tcp: If ``True``, use TCP to make the query. + :type tcp: bool + :param resolver: The resolver to use. If ``None``, the default resolver + is used. + :type resolver: :py:class:`dns.resolver.Resolver` or ``None`` + :param lifetime: Total time to allow for the queries. If ``None``, only + the individual query limits of the resolver apply. + :type lifetime: float or ``None`` + :raises dns.resolver.NoRootSOA: If there is no SOA RR at the DNS root. + :raises dns.resolver.LifetimeTimeout: If the answer could not be found + within the allotted lifetime. + :rtype: :py:class:`dns.name.Name` """ if isinstance(name, str): @@ -1752,20 +1732,18 @@ def make_resolver_at( ) -> Resolver: """Make a stub resolver using the specified destination as the full resolver. - *where*, a ``dns.name.Name`` or ``str`` the domain name or IP address of the - full resolver. - - *port*, an ``int``, the port to use. If not specified, the default is 53. - - *family*, an ``int``, the address family to use. This parameter is used if - *where* is not an address. The default is ``socket.AF_UNSPEC`` in which case - the first address returned by ``resolve_name()`` will be used, otherwise the - first address of the specified family will be used. - - *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use for - resolution of hostnames. If not specified, the default resolver will be used. - - Returns a ``dns.resolver.Resolver`` or raises an exception. + :param where: The domain name or IP address of the full resolver. + :type where: :py:class:`dns.name.Name` or str + :param port: The port to use. Default is 53. + :type port: int + :param family: The address family. Used only when *where* is not an + address literal. ``socket.AF_UNSPEC`` (default) uses the first + address returned; otherwise the first address of the given family. + :type family: int + :param resolver: The resolver to use for hostname resolution. If + ``None``, the default resolver is used. + :type resolver: :py:class:`dns.resolver.Resolver` or ``None`` + :rtype: :py:class:`dns.resolver.Resolver` """ if resolver is None: resolver = get_default_resolver() diff --git a/dns/reversename.py b/dns/reversename.py index 60a4e839..53c95693 100644 --- a/dns/reversename.py +++ b/dns/reversename.py @@ -36,20 +36,17 @@ def from_address( """Convert an IPv4 or IPv6 address in textual form into a Name object whose value is the reverse-map domain name of the address. - *text*, a ``str``, is an IPv4 or IPv6 address in textual form - (e.g. '127.0.0.1', '::1') - - *v4_origin*, a ``dns.name.Name`` to append to the labels corresponding to - the address if the address is an IPv4 address, instead of the default - (in-addr.arpa.) - - *v6_origin*, a ``dns.name.Name`` to append to the labels corresponding to - the address if the address is an IPv6 address, instead of the default - (ip6.arpa.) - - Raises ``dns.exception.SyntaxError`` if the address is badly formed. - - Returns a ``dns.name.Name``. + :param text: An IPv4 or IPv6 address in textual form (e.g. ``'127.0.0.1'``, + ``'::1'``). + :type text: str + :param v4_origin: Domain to append for IPv4 addresses instead of + ``in-addr.arpa.`` + :type v4_origin: :py:class:`dns.name.Name` + :param v6_origin: Domain to append for IPv6 addresses instead of + ``ip6.arpa.`` + :type v6_origin: :py:class:`dns.name.Name` + :raises dns.exception.SyntaxError: If the address is badly formed. + :rtype: :py:class:`dns.name.Name` """ try: @@ -73,19 +70,17 @@ def to_address( ) -> str: """Convert a reverse map domain name into textual address form. - *name*, a ``dns.name.Name``, an IPv4 or IPv6 address in reverse-map name - form. - - *v4_origin*, a ``dns.name.Name`` representing the top-level domain for - IPv4 addresses, instead of the default (in-addr.arpa.) - - *v6_origin*, a ``dns.name.Name`` representing the top-level domain for - IPv4 addresses, instead of the default (ip6.arpa.) - - Raises ``dns.exception.SyntaxError`` if the name does not have a - reverse-map form. - - Returns a ``str``. + :param name: An IPv4 or IPv6 address in reverse-map name form. + :type name: :py:class:`dns.name.Name` + :param v4_origin: Top-level domain for IPv4 addresses (default + ``in-addr.arpa.``). + :type v4_origin: :py:class:`dns.name.Name` + :param v6_origin: Top-level domain for IPv6 addresses (default + ``ip6.arpa.``). + :type v6_origin: :py:class:`dns.name.Name` + :raises dns.exception.SyntaxError: If the name does not have a + reverse-map form. + :rtype: str """ if name.is_subdomain(v4_origin): diff --git a/dns/rrset.py b/dns/rrset.py index 19501c68..19fd7a5f 100644 --- a/dns/rrset.py +++ b/dns/rrset.py @@ -146,17 +146,15 @@ class RRset(dns.rdataset.Rdataset): Any additional keyword arguments are passed on to the rdata ``to_text()`` method. - *origin*, a ``dns.name.Name`` or ``None``, the origin for relative - names. - - *relativize*, a ``bool``. If ``True``, names will be relativized - to *origin*. - - *want_comments*, a ``bool``. If ``True``, emit comments for rdata - which have them. The default is ``False``. - - *style*, a :py:class:`dns.rdataset.RdatasetStyle` or ``None`` (the default). If - specified, the style overrides the other parameters. + :param origin: The origin for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param relativize: If ``True``, names will be relativized to *origin*. + :type relativize: bool + :param want_comments: If ``True``, emit comments for rdata which have + them. The default is ``False``. + :type want_comments: bool + :param style: If specified, overrides the other parameters. + :type style: :py:class:`dns.rdataset.RdatasetStyle` or ``None`` """ if style is None: kw = kw.copy() @@ -175,7 +173,7 @@ class RRset(dns.rdataset.Rdataset): *style*, a :py:class:`dns.rdataset.RdatasetStyle` or ``None`` (the default). If specified, the style overrides the other parameters. - returns a ``str``. + :rtype: str """ if self.deleting is not None: style = style.replace(override_rdclass=self.deleting) @@ -193,7 +191,8 @@ class RRset(dns.rdataset.Rdataset): All keyword arguments are passed to ``dns.rdataset.to_wire()``; see that function for details. - Returns an ``int``, the number of records emitted. + :returns: The number of records emitted. + :rtype: int """ return super().to_wire(self.name, file, compress, origin, self.deleting, **kw) @@ -203,7 +202,7 @@ class RRset(dns.rdataset.Rdataset): def to_rdataset(self) -> dns.rdataset.Rdataset: """Convert an RRset into an Rdataset. - Returns a ``dns.rdataset.Rdataset``. + :rtype: :py:class:`dns.rdataset.Rdataset` """ return dns.rdataset.from_rdata_list(self.ttl, list(self)) @@ -222,19 +221,17 @@ def from_text_list( """Create an RRset with the specified name, TTL, class, and type, and with the specified list of rdatas in text format. - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use; if ``None``, the default IDNA 2003 - encoder/decoder is used. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - Returns a ``dns.rrset.RRset`` object. + :param idna_codec: Specifies the IDNA encoder/decoder. If ``None``, the + default IDNA 2003 encoder/decoder is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param origin: The origin to use for relative names. + :type origin: :py:class:`dns.name.Name` or ``None`` + :param relativize: If ``True``, names will be relativized. + :type relativize: bool + :param relativize_to: The origin to use when relativizing names. If not + set, *origin* is used. + :type relativize_to: :py:class:`dns.name.Name` or ``None`` + :rtype: :py:class:`dns.rrset.RRset` """ if isinstance(name, str): @@ -261,7 +258,7 @@ def from_text( """Create an RRset with the specified name, TTL, class, and type and with the specified rdatas in text format. - Returns a ``dns.rrset.RRset`` object. + :rtype: :py:class:`dns.rrset.RRset` """ return from_text_list( @@ -278,12 +275,10 @@ def from_rdata_list( """Create an RRset with the specified name and TTL, and with the specified list of rdata objects. - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use; if ``None``, the default IDNA 2003 - encoder/decoder is used. - - Returns a ``dns.rrset.RRset`` object. - + :param idna_codec: Specifies the IDNA encoder/decoder. If ``None``, the + default IDNA 2003 encoder/decoder is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :rtype: :py:class:`dns.rrset.RRset` """ if isinstance(name, str): @@ -305,7 +300,7 @@ def from_rdata(name: dns.name.Name | str, ttl: int, *rdatas: Any) -> RRset: """Create an RRset with the specified name and TTL, and with the specified rdata objects. - Returns a ``dns.rrset.RRset`` object. + :rtype: :py:class:`dns.rrset.RRset` """ return from_rdata_list(name, ttl, cast(Collection[dns.rdata.Rdata], rdatas)) diff --git a/dns/set.py b/dns/set.py index 9db0bf61..8f316c80 100644 --- a/dns/set.py +++ b/dns/set.py @@ -276,7 +276,7 @@ class Set: def issubset(self, other): """Is this set a subset of *other*? - Returns a ``bool``. + :rtype: bool """ if not isinstance(other, Set): @@ -289,7 +289,7 @@ class Set: def issuperset(self, other): """Is this set a superset of *other*? - Returns a ``bool``. + :rtype: bool """ if not isinstance(other, Set): diff --git a/dns/transaction.py b/dns/transaction.py index 8ce14eb4..3a5dec5d 100644 --- a/dns/transaction.py +++ b/dns/transaction.py @@ -24,37 +24,33 @@ class TransactionManager: def writer(self, replacement: bool = False) -> "Transaction": """Begin a writable transaction. - *replacement*, a ``bool``. If `True`, the content of the - transaction completely replaces any prior content. If False, - the default, then the content of the transaction updates the - existing content. + :param bool replacement: If ``True``, the content of the transaction + completely replaces any prior content. If ``False`` (the default), + the content of the transaction updates the existing content. """ raise NotImplementedError # pragma: no cover def origin_information( self, ) -> tuple[dns.name.Name | None, bool, dns.name.Name | None]: - """Returns a tuple - - (absolute_origin, relativize, effective_origin) - - giving the absolute name of the default origin for any - relative domain names, the "effective origin", and whether - names should be relativized. The "effective origin" is the - absolute origin if relativize is False, and the empty name if - relativize is true. (The effective origin is provided even - though it can be computed from the absolute_origin and - relativize setting because it avoids a lot of code - duplication.) - - If the returned names are `None`, then no origin information is - available. + """Return origin information for the transaction manager. This information is used by code working with transactions to allow it to coordinate relativization. The transaction code itself takes what it gets (i.e. does not change name relativity). + :returns: A tuple ``(absolute_origin, relativize, effective_origin)`` + giving the absolute name of the default origin for any relative + domain names, whether names should be relativized, and the + "effective origin". The effective origin is the absolute origin if + *relativize* is ``False``, and the empty name if *relativize* is + ``True``. (The effective origin is provided even though it can be + computed from the absolute origin and relativize setting because it + avoids a lot of code duplication.) If the returned names are + ``None``, then no origin information is available. + :rtype: tuple[:py:class:`dns.name.Name` or ``None``, bool, + :py:class:`dns.name.Name` or ``None``] """ raise NotImplementedError # pragma: no cover @@ -135,7 +131,7 @@ class Transaction: covers: dns.rdatatype.RdataType | str = dns.rdatatype.NONE, ) -> dns.rdataset.Rdataset: """Return the rdataset associated with *name*, *rdtype*, and *covers*, - or `None` if not found. + or ``None`` if not found. Note that the returned rdataset is immutable. """ @@ -150,7 +146,8 @@ class Transaction: def get_node(self, name: dns.name.Name) -> dns.node.Node | None: """Return the node at *name*, if any. - Returns an immutable node or ``None``. + :returns: An immutable node, or ``None`` if *name* does not exist. + :rtype: :py:class:`dns.node.ImmutableNode` or ``None`` """ return _ensure_immutable_node(self._get_node(name)) @@ -231,9 +228,8 @@ class Transaction: - name, rdata... - Raises dns.transaction.DeleteNotExact if some of the records - are not in the existing set. - + :raises: :py:exc:`dns.transaction.DeleteNotExact` if some of the + records are not in the existing set. """ self._check_ended() self._check_read_only() @@ -254,14 +250,16 @@ class Transaction: ) -> None: """Update the serial number. - *value*, an `int`, is an increment if *relative* is `True`, or the - actual value to set if *relative* is `False`. - - Raises `KeyError` if there is no SOA rdataset at *name*. - - Raises `ValueError` if *value* is negative or if the increment is - so large that it would cause the new serial to be less than the - prior value. + :param int value: An increment if *relative* is ``True``, or the + actual value to set if *relative* is ``False``. + :param bool relative: Whether *value* is a relative increment or an + absolute value. The default is ``True``. + :param name: The name of the SOA record to update. + :type name: :py:class:`dns.name.Name` + :raises KeyError: If there is no SOA rdataset at *name*. + :raises ValueError: If *value* is negative or if the increment is + so large that it would cause the new serial to be less than the + prior value. """ self._check_ended() if value < 0: @@ -292,9 +290,9 @@ class Transaction: def changed(self) -> bool: """Has this transaction changed anything? - For read-only transactions, the result is always `False`. + For read-only transactions, the result is always ``False``. - For writable transactions, the result is `True` if at some time + For writable transactions, the result is ``True`` if at some time during the life of the transaction, the content was changed. """ self._check_ended() @@ -305,11 +303,11 @@ class Transaction: Normally transactions are used as context managers and commit or rollback automatically, but it may be done explicitly if needed. - A ``dns.transaction.Ended`` exception will be raised if you try - to use a transaction after it has been committed or rolled back. - Raises an exception if the commit fails (in which case the transaction - is also rolled back. + :raises: :py:exc:`dns.transaction.AlreadyEnded` if the transaction + has already been committed or rolled back. + :raises: An exception if the commit fails, in which case the + transaction is also rolled back. """ self._end(True) @@ -318,10 +316,10 @@ class Transaction: Normally transactions are used as context managers and commit or rollback automatically, but it may be done explicitly if needed. - A ``dns.transaction.AlreadyEnded`` exception will be raised if you try - to use a transaction after it has been committed or rolled back. - Rollback cannot otherwise fail. + + :raises: :py:exc:`dns.transaction.AlreadyEnded` if the transaction + has already been committed or rolled back. """ self._end(False) @@ -366,20 +364,20 @@ class Transaction: self, ) -> Iterator[tuple[dns.name.Name, dns.rdataset.Rdataset]]: """Iterate all the rdatasets in the transaction, returning - (`dns.name.Name`, `dns.rdataset.Rdataset`) tuples. + (:py:class:`dns.name.Name`, :py:class:`dns.rdataset.Rdataset`) tuples. - Note that as is usual with python iterators, adding or removing items - while iterating will invalidate the iterator and may raise `RuntimeError` - or fail to iterate over all entries.""" + Note that as is usual with Python iterators, adding or removing items + while iterating will invalidate the iterator and may raise + :py:exc:`RuntimeError` or fail to iterate over all entries.""" self._check_ended() return self._iterate_rdatasets() def iterate_names(self) -> Iterator[dns.name.Name]: """Iterate all the names in the transaction. - Note that as is usual with python iterators, adding or removing names - while iterating will invalidate the iterator and may raise `RuntimeError` - or fail to iterate over all entries.""" + Note that as is usual with Python iterators, adding or removing names + while iterating will invalidate the iterator and may raise + :py:exc:`RuntimeError` or fail to iterate over all entries.""" self._check_ended() return self._iterate_names() @@ -578,7 +576,7 @@ class Transaction: def _get_rdataset(self, name, rdtype, covers): """Return the rdataset associated with *name*, *rdtype*, and *covers*, - or `None` if not found. + or ``None`` if not found. """ raise NotImplementedError # pragma: no cover @@ -603,7 +601,7 @@ class Transaction: def _name_exists(self, name): """Does name exist? - Returns a bool. + :rtype: bool """ raise NotImplementedError # pragma: no cover @@ -614,11 +612,9 @@ class Transaction: def _end_transaction(self, commit): """End the transaction. - *commit*, a bool. If ``True``, commit the transaction, otherwise - roll it back. - - If committing and the commit fails, then roll back and raise an - exception. + :param bool commit: If ``True``, commit the transaction; otherwise + roll it back. If committing and the commit fails, then roll back + and raise an exception. """ raise NotImplementedError # pragma: no cover @@ -642,7 +638,8 @@ class Transaction: def _get_node(self, name): """Return the node at *name*, if any. - Returns a node or ``None``. + :returns: The node, or ``None`` if *name* does not exist. + :rtype: :py:class:`dns.node.Node` or ``None`` """ raise NotImplementedError # pragma: no cover diff --git a/dns/ttl.py b/dns/ttl.py index 16289cd0..11f6015b 100644 --- a/dns/ttl.py +++ b/dns/ttl.py @@ -36,11 +36,10 @@ def from_text(text: str) -> int: The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported. - *text*, a ``str``, the textual TTL. - - Raises ``dns.ttl.BadTTL`` if the TTL is not well-formed. - - Returns an ``int``. + :param text: The textual TTL. + :type text: str + :raises dns.ttl.BadTTL: If the TTL is not well-formed. + :rtype: int """ if text.isdigit(): diff --git a/dns/update.py b/dns/update.py index 26e3ebfe..7ccf402f 100644 --- a/dns/update.py +++ b/dns/update.py @@ -63,12 +63,12 @@ class UpdateMessage(dns.message.Message): # lgtm[py/missing-equals] See the documentation of the Message class for a complete description of the keyring dictionary. - *zone*, a ``dns.name.Name``, ``str``, or ``None``, the zone - which is being updated. ``None`` should only be used by dnspython's - message constructors, as a zone is required for the convenience - methods like ``add()``, ``replace()``, etc. - - *rdclass*, an ``int`` or ``str``, the class of the zone. + :param zone: The zone which is being updated. ``None`` should only be + used by dnspython's message constructors, as a zone is required for + the convenience methods like ``add()``, ``replace()``, etc. + :type zone: :py:class:`dns.name.Name`, str, or ``None`` + :param rdclass: The class of the zone. + :type rdclass: int or str The *keyring*, *keyname*, and *keyalgorithm* parameters are passed to ``use_tsig()``; see its documentation for details. diff --git a/dns/versioned.py b/dns/versioned.py index 683c5930..5bb8ae75 100644 --- a/dns/versioned.py +++ b/dns/versioned.py @@ -52,18 +52,20 @@ class Zone(dns.zone.Zone): # lgtm[py/missing-equals] ): """Initialize a versioned zone object. - *origin* is the origin of the zone. It may be a ``dns.name.Name``, - a ``str``, or ``None``. If ``None``, then the zone's origin will - be set by the first ``$ORIGIN`` line in a zone file. - - *rdclass*, an ``int``, the zone's rdata class; the default is class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - - *pruning policy*, a function taking a ``Zone`` and a ``Version`` and returning - a ``bool``, or ``None``. Should the version be pruned? If ``None``, - the default policy, which retains one version is used. + :param origin: The origin of the zone. It may be a + :py:class:`dns.name.Name`, a ``str``, or ``None``. If ``None``, + then the zone's origin will be set by the first ``$ORIGIN`` line + in a zone file. + :type origin: :py:class:`dns.name.Name`, str, or ``None`` + :param rdclass: The zone's rdata class; the default is class IN. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param bool relativize: Whether domain names are relativized to the + zone's origin. The default is ``True``. + :param pruning_policy: A callable taking a + :py:class:`dns.versioned.Zone` and a :py:class:`dns.zone.Version` + and returning a ``bool`` if the version should be pruned. If + ``None``, the default policy (retain one version) is used. + :type pruning_policy: Callable or ``None`` """ super().__init__(origin, rdclass, relativize) self._versions: collections.deque[Version] = collections.deque() @@ -201,7 +203,11 @@ class Zone(dns.zone.Zone): # lgtm[py/missing-equals] def set_max_versions(self, max_versions: int | None) -> None: """Set a pruning policy that retains up to the specified number - of versions + of versions. + + :param max_versions: The maximum number of versions to retain, or + ``None`` for no limit. + :type max_versions: int or ``None`` """ if max_versions is not None and max_versions < 1: raise ValueError("max versions must be at least 1") @@ -222,14 +228,18 @@ class Zone(dns.zone.Zone): # lgtm[py/missing-equals] ) -> None: """Set the pruning policy for the zone. - The *policy* function takes a `Version` and returns `True` if - the version should be pruned, and `False` otherwise. `None` - may also be specified for policy, in which case the default policy - is used. + The *policy* function takes a :py:class:`dns.zone.Version` and returns + ``True`` if the version should be pruned, and ``False`` otherwise. + ``None`` may also be specified for policy, in which case the default + policy is used. Pruning checking proceeds from the least version and the first - time the function returns `False`, the checking stops. I.e. the + time the function returns ``False``, the checking stops. I.e. the retained versions are always a consecutive sequence. + + :param policy: The pruning policy callable, or ``None`` to use the + default policy. + :type policy: Callable or ``None`` """ if policy is None: policy = self._default_pruning_policy diff --git a/dns/wirebase.py b/dns/wirebase.py index 299558c3..21ffd524 100644 --- a/dns/wirebase.py +++ b/dns/wirebase.py @@ -13,12 +13,12 @@ class Parser: """Helper class for parsing DNS wire format.""" def __init__(self, wire: bytes, current: int = 0): - """Initialize a Parser + """Initialize a Parser. - *wire*, a ``bytes`` contains the data to be parsed, and possibly other data. - Typically it is the whole message or a slice of it. - - *current*, an `int`, the offset within *wire* where parsing should begin. + :param wire: The data to be parsed (typically a whole message or a slice of it). + :type wire: bytes + :param current: The offset within *wire* where parsing should begin. + :type current: int """ self.wire = wire self.current = 0 diff --git a/dns/xfr.py b/dns/xfr.py index 0f4c7f36..4550fa6f 100644 --- a/dns/xfr.py +++ b/dns/xfr.py @@ -71,8 +71,8 @@ class Inbound: *serial* is the base serial number for IXFRs, and is required in that case. - *is_udp*, a ``bool`` indidicates if UDP is being used for this - XFR. + :param is_udp: Whether UDP is being used for this XFR. + :type is_udp: bool """ self.txn_manager = txn_manager self.txn: dns.transaction.Transaction | None = None @@ -278,22 +278,22 @@ def make_query( ) -> tuple[dns.message.QueryMessage, int | None]: """Make an AXFR or IXFR query. - *txn_manager* is a ``dns.transaction.TransactionManager``, typically a - ``dns.zone.Zone``. - - *serial* is an ``int`` or ``None``. If 0, then IXFR will be - attempted using the most recent serial number from the - *txn_manager*; it is the caller's responsibility to ensure there - are no write transactions active that could invalidate the - retrieved serial. If a serial cannot be determined, AXFR will be - forced. Other integer values are the starting serial to use. - ``None`` forces an AXFR. + :param txn_manager: The transaction manager for this transfer, typically + a :py:class:`dns.zone.Zone`. + :type txn_manager: :py:class:`dns.transaction.TransactionManager` + :param serial: If ``0``, IXFR is attempted using the most recent serial + from *txn_manager* (caller must ensure no write transactions are + active that could invalidate the retrieved serial). If a serial + cannot be determined, AXFR is forced. Other integer values are the + starting serial to use. ``None`` forces an AXFR. + :type serial: int or ``None`` Please see the documentation for :py:func:`dns.message.make_query` and :py:func:`dns.message.Message.use_tsig` for details on the other parameters to this function. - Returns a `(query, serial)` tuple. + :returns: A ``(query, serial)`` tuple. + :rtype: tuple """ zone_origin, _, origin = txn_manager.origin_information() if zone_origin is None: diff --git a/dns/zone.py b/dns/zone.py index 13fbb40e..638b04c3 100644 --- a/dns/zone.py +++ b/dns/zone.py @@ -108,31 +108,28 @@ def _validate_name( @dataclasses.dataclass(frozen=True) class ZoneStyle(dns.node.NodeStyle): - """Zone text styles + """Zone text styles. - A ``ZoneStyle`` is also a :py:class:`dns.name.NameStyle` and a - :py:class:`dns.rdata.RdataStyle`, a :py:class:`dns.rdataset.RdatasetStyle`, - and a :py:class:`dns.node.NodeStyle`. + A :py:class:`dns.zone.ZoneStyle` is also a :py:class:`dns.name.NameStyle`, + :py:class:`dns.rdata.RdataStyle`, :py:class:`dns.rdataset.RdatasetStyle`, + and :py:class:`dns.node.NodeStyle`. See those classes for a description of their options. - *sorted*, a ``bool``. If True, the default, then the file - will be written with the names sorted in DNSSEC order from - least to greatest. Otherwise the names will be written in - whatever order they happen to have in the zone's dictionary. - - *nl*, a ``str`` or ``None`` (the default). The end of line string, - or if ``None``, the output will use the platform's native - end-of-line marker (i.e. LF on POSIX, CRLF on Windows). - - *want_origin*, a ``bool``. If ``True``, emit a $ORIGIN line at - the start of the output. If ``False``, the default, do not emit - one. - - *want_unicode_directive*, a ``bool``. If ``True`` and the zone - has a non-empty ``unicode`` attribute, then emit a ``$UNICODE`` - line in the output. This directive is not standard, but allows - dnspython and other aware software to read and write Unicode zonefiles - without changing the rendering of names and TXT-like records. + :param bool sorted: If ``True`` (the default), the file will be written + with the names sorted in DNSSEC order from least to greatest. + Otherwise the names will be written in whatever order they happen + to have in the zone's dictionary. + :param nl: The end of line string. If ``None`` (the default), the + output will use the platform's native end-of-line marker (i.e. LF + on POSIX, CRLF on Windows). + :type nl: str or ``None`` + :param bool want_origin: If ``True``, emit a ``$ORIGIN`` line at the + start of the output. If ``False`` (the default), do not emit one. + :param bool want_unicode_directive: If ``True`` and the zone has a + non-empty ``unicode`` attribute, then emit a ``$UNICODE`` line in + the output. This directive is not standard, but allows dnspython + and other aware software to read and write Unicode zonefiles without + changing the rendering of names and TXT-like records. """ sorted: bool = True @@ -169,14 +166,15 @@ class Zone(dns.transaction.TransactionManager): ): """Initialize a zone object. - *origin* is the origin of the zone. It may be a ``dns.name.Name``, - a ``str``, or ``None``. If ``None``, then the zone's origin will - be set by the first ``$ORIGIN`` line in a zone file. - - *rdclass*, an ``int``, the zone's rdata class; the default is class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. + :param origin: The origin of the zone. It may be a + :py:class:`dns.name.Name`, a ``str``, or ``None``. If ``None``, + then the zone's origin will be set by the first ``$ORIGIN`` line + in a zone file. + :type origin: :py:class:`dns.name.Name`, str, or ``None`` + :param rdclass: The zone's rdata class; the default is class IN. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param bool relativize: Whether domain names are relativized to the + zone's origin. The default is ``True``. """ if origin is not None: @@ -196,7 +194,7 @@ class Zone(dns.transaction.TransactionManager): """Two zones are equal if they have the same origin, class, and nodes. - Returns a ``bool``. + :rtype: bool """ if not isinstance(other, Zone): @@ -212,7 +210,7 @@ class Zone(dns.transaction.TransactionManager): def __ne__(self, other): """Are two zones not equal? - Returns a ``bool``. + :rtype: bool """ return not self.__eq__(other) @@ -263,18 +261,16 @@ class Zone(dns.transaction.TransactionManager): ) -> dns.node.Node: """Find a node in the zone, possibly creating it. - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.node.Node``. + :param name: The name of the node to find. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param bool create: If ``True``, the node will be created if it does + not exist. + :raises KeyError: if the name is not known and *create* was not + specified, or if the name was not a subdomain of the origin. + :rtype: :py:class:`dns.node.Node` """ name = self._validate_name(name) @@ -291,19 +287,18 @@ class Zone(dns.transaction.TransactionManager): ) -> dns.node.Node | None: """Get a node in the zone, possibly creating it. - This method is like ``find_node()``, except it returns None instead - of raising an exception if the node does not exist and creation - has not been requested. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Returns a ``dns.node.Node`` or ``None``. + This method is like :py:meth:`find_node`, except it returns ``None`` + instead of raising an exception if the node does not exist and + creation has not been requested. + + :param name: The name of the node to find. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param bool create: If ``True``, the node will be created if it does + not exist. + :rtype: :py:class:`dns.node.Node` or ``None`` """ try: @@ -315,12 +310,13 @@ class Zone(dns.transaction.TransactionManager): def delete_node(self, name: dns.name.Name | str) -> None: """Delete the specified node if it exists. - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - It is not an error if the node does not exist. + + :param name: The name of the node to delete. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str """ name = self._validate_name(name) @@ -340,32 +336,24 @@ class Zone(dns.transaction.TransactionManager): The rdataset returned is not a copy; changes to it will change the zone. - KeyError is raised if the name or type are not found. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str`` the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.rdataset.Rdataset``. + :param name: The name of the node to find. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param rdtype: The rdata type desired. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str + :param covers: The covered type. Usually :py:attr:`dns.rdatatype.NONE`, + but if *rdtype* is :py:attr:`dns.rdatatype.SIG` or + :py:attr:`dns.rdatatype.RRSIG`, then this is the rdata type the + SIG/RRSIG covers. The library treats the SIG and RRSIG types as + a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` or str + :param bool create: If ``True``, the node will be created if it does + not exist. + :raises KeyError: if the name or type are not found and *create* was + not specified, or if the name was not a subdomain of the origin. + :rtype: :py:class:`dns.rdataset.Rdataset` """ name = self._validate_name(name) @@ -383,37 +371,29 @@ class Zone(dns.transaction.TransactionManager): ) -> dns.rdataset.Rdataset | None: """Look for an rdataset with the specified name and type in the zone. - This method is like ``find_rdataset()``, except it returns None instead - of raising an exception if the rdataset does not exist and creation - has not been requested. + This method is like :py:meth:`find_rdataset`, except it returns + ``None`` instead of raising an exception if the rdataset does not + exist and creation has not been requested. The rdataset returned is not a copy; changes to it will change the zone. - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.rdataset.Rdataset`` or ``None``. + :param name: The name of the node to find. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param rdtype: The rdata type desired. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str + :param covers: The covered type. Usually :py:attr:`dns.rdatatype.NONE`, + but if *rdtype* is :py:attr:`dns.rdatatype.SIG` or + :py:attr:`dns.rdatatype.RRSIG`, then this is the rdata type the + SIG/RRSIG covers. The library treats the SIG and RRSIG types as + a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` or str + :param bool create: If ``True``, the node will be created if it does + not exist. + :rtype: :py:class:`dns.rdataset.Rdataset` or ``None`` """ try: @@ -431,24 +411,23 @@ class Zone(dns.transaction.TransactionManager): """Delete the rdataset matching *rdtype* and *covers*, if it exists at the node specified by *name*. - It is not an error if the node does not exist, or if there is no matching - rdataset at the node. - - If the node has no rdatasets after the deletion, it will itself be deleted. - - *name*: the name of the node to find. The value may be a ``dns.name.Name`` or a - ``str``. If absolute, the name must be a subdomain of the zone's origin. If - ``zone.relativize`` is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str`` or ``None``, the covered - type. Usually this value is ``dns.rdatatype.NONE``, but if the rdtype is - ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, then the covers value will be - the rdata type the SIG/RRSIG covers. The library treats the SIG and RRSIG types - as if they were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This - makes RRSIGs much easier to work with than if RRSIGs covering different rdata - types were aggregated into a single RRSIG rdataset. + It is not an error if the node does not exist, or if there is no + matching rdataset at the node. If the node has no rdatasets after + the deletion, it will itself be deleted. + + :param name: The name of the node. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param rdtype: The rdata type desired. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str + :param covers: The covered type. Usually :py:attr:`dns.rdatatype.NONE`, + but if *rdtype* is :py:attr:`dns.rdatatype.SIG` or + :py:attr:`dns.rdatatype.RRSIG`, then this is the rdata type the + SIG/RRSIG covers. The library treats the SIG and RRSIG types as + a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` or str """ name = self._validate_name(name) @@ -465,20 +444,20 @@ class Zone(dns.transaction.TransactionManager): ) -> None: """Replace an rdataset at name. - It is not an error if there is no rdataset matching I{replacement}. + It is not an error if there is no rdataset matching *replacement*. Ownership of the *replacement* object is transferred to the zone; in other words, this method does not store a copy of *replacement* - at the node, it stores *replacement* itself. - - If the node does not exist, it is created. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *replacement*, a ``dns.rdataset.Rdataset``, the replacement rdataset. + at the node, it stores *replacement* itself. If the node does not + exist, it is created. + + :param name: The name of the node. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param replacement: The replacement rdataset. + :type replacement: :py:class:`dns.rdataset.Rdataset` """ if replacement.rdclass != self.rdclass: @@ -496,38 +475,30 @@ class Zone(dns.transaction.TransactionManager): and return an RRset encapsulating it. This method is less efficient than the similar - ``find_rdataset()`` because it creates an RRset instead of - returning the matching rdataset. It may be more convenient - for some uses since it returns an object which binds the owner - name to the rdataset. + :py:meth:`find_rdataset` because it creates an RRset instead of + returning the matching rdataset. It may be more convenient for some + uses since it returns an object which binds the owner name to the + rdataset. This method may not be used to create new nodes or rdatasets; - use ``find_rdataset`` instead. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.rrset.RRset`` or ``None``. + use :py:meth:`find_rdataset` instead. + + :param name: The name of the node to find. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param rdtype: The rdata type desired. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str + :param covers: The covered type. Usually :py:attr:`dns.rdatatype.NONE`, + but if *rdtype* is :py:attr:`dns.rdatatype.SIG` or + :py:attr:`dns.rdatatype.RRSIG`, then this is the rdata type the + SIG/RRSIG covers. The library treats the SIG and RRSIG types as + a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` or str + :raises KeyError: if the name or type are not found, or if the name + was not a subdomain of the origin. + :rtype: :py:class:`dns.rrset.RRset` """ vname = self._validate_name(name) @@ -547,35 +518,28 @@ class Zone(dns.transaction.TransactionManager): """Look for an rdataset with the specified name and type in the zone, and return an RRset encapsulating it. - This method is less efficient than the similar ``get_rdataset()`` + This method is less efficient than the similar :py:meth:`get_rdataset` because it creates an RRset instead of returning the matching - rdataset. It may be more convenient for some uses since it - returns an object which binds the owner name to the rdataset. + rdataset. It may be more convenient for some uses since it returns + an object which binds the owner name to the rdataset. This method may not be used to create new nodes or rdatasets; - use ``get_rdataset()`` instead. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Returns a ``dns.rrset.RRset`` or ``None``. + use :py:meth:`get_rdataset` instead. + + :param name: The name of the node to find. The value may be a + :py:class:`dns.name.Name` or a ``str``. If absolute, the name + must be a subdomain of the zone's origin. If ``zone.relativize`` + is ``True``, then the name will be relativized. + :type name: :py:class:`dns.name.Name` or str + :param rdtype: The rdata type desired. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str + :param covers: The covered type. Usually :py:attr:`dns.rdatatype.NONE`, + but if *rdtype* is :py:attr:`dns.rdatatype.SIG` or + :py:attr:`dns.rdatatype.RRSIG`, then this is the rdata type the + SIG/RRSIG covers. The library treats the SIG and RRSIG types as + a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` or str + :rtype: :py:class:`dns.rrset.RRset` or ``None`` """ try: @@ -589,22 +553,19 @@ class Zone(dns.transaction.TransactionManager): rdtype: dns.rdatatype.RdataType | str = dns.rdatatype.ANY, covers: dns.rdatatype.RdataType | str = dns.rdatatype.NONE, ) -> Iterator[tuple[dns.name.Name, dns.rdataset.Rdataset]]: - """Return a generator which yields (name, rdataset) tuples for - all rdatasets in the zone which have the specified *rdtype* - and *covers*. If *rdtype* is ``dns.rdatatype.ANY``, the default, + """Return a generator which yields ``(name, rdataset)`` tuples for + all rdatasets in the zone which have the specified *rdtype* and + *covers*. If *rdtype* is :py:attr:`dns.rdatatype.ANY` (the default), then all rdatasets will be matched. - *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. + :param rdtype: The rdata type desired. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str + :param covers: The covered type. Usually :py:attr:`dns.rdatatype.NONE`, + but if *rdtype* is :py:attr:`dns.rdatatype.SIG` or + :py:attr:`dns.rdatatype.RRSIG`, then this is the rdata type the + SIG/RRSIG covers. The library treats the SIG and RRSIG types as + a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` or str """ rdtype = dns.rdatatype.RdataType.make(rdtype) @@ -621,22 +582,19 @@ class Zone(dns.transaction.TransactionManager): rdtype: dns.rdatatype.RdataType | str = dns.rdatatype.ANY, covers: dns.rdatatype.RdataType | str = dns.rdatatype.NONE, ) -> Iterator[tuple[dns.name.Name, int, dns.rdata.Rdata]]: - """Return a generator which yields (name, ttl, rdata) tuples for - all rdatas in the zone which have the specified *rdtype* - and *covers*. If *rdtype* is ``dns.rdatatype.ANY``, the default, - then all rdatas will be matched. - - *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. + """Return a generator which yields ``(name, ttl, rdata)`` tuples for + all rdatas in the zone which have the specified *rdtype* and *covers*. + If *rdtype* is :py:attr:`dns.rdatatype.ANY` (the default), then all + rdatas will be matched. + + :param rdtype: The rdata type desired. + :type rdtype: :py:class:`dns.rdatatype.RdataType` or str + :param covers: The covered type. Usually :py:attr:`dns.rdatatype.NONE`, + but if *rdtype* is :py:attr:`dns.rdatatype.SIG` or + :py:attr:`dns.rdatatype.RRSIG`, then this is the rdata type the + SIG/RRSIG covers. The library treats the SIG and RRSIG types as + a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). + :type covers: :py:class:`dns.rdatatype.RdataType` or str """ rdtype = dns.rdatatype.RdataType.make(rdtype) @@ -661,29 +619,25 @@ class Zone(dns.transaction.TransactionManager): ) -> None: """Write a zone to a file. - *f*, a file or `str`. If *f* is a string, it is treated - as the name of a file to open. - - *sorted*, a ``bool``. If True, the default, then the file - will be written with the names sorted in DNSSEC order from - least to greatest. Otherwise the names will be written in - whatever order they happen to have in the zone's dictionary. - - *relativize*, a ``bool``. If True, the default, then domain - names in the output will be relativized to the zone's origin - if possible. - - *nl*, a ``str``, ``bytes``, or None. The end of line string. If not - ``None``, the output will use the platform's native - end-of-line marker (i.e. LF on POSIX, CRLF on Windows). - - *want_comments*, a ``bool``. If ``True``, emit end-of-line comments - as part of writing the file. If ``False``, the default, do not - emit them. - - *want_origin*, a ``bool``. If ``True``, emit a $ORIGIN line at - the start of the file. If ``False``, the default, do not emit - one. + :param f: A file object or a ``str`` filename. If a string, it is + treated as the name of a file to open. + :param bool sorted: If ``True`` (the default), the file will be + written with the names sorted in DNSSEC order from least to + greatest. Otherwise the names will be written in whatever order + they happen to have in the zone's dictionary. + :param bool relativize: If ``True`` (the default), domain names in + the output will be relativized to the zone's origin if possible. + :param nl: The end of line string. If ``None`` (the default), the + output will use the platform's native end-of-line marker (i.e. LF + on POSIX, CRLF on Windows). + :type nl: str, bytes, or ``None`` + :param bool want_comments: If ``True``, emit end-of-line comments as + part of writing the file. If ``False`` (the default), do not + emit them. + :param bool want_origin: If ``True``, emit a ``$ORIGIN`` line at the + start of the file. If ``False`` (the default), do not emit one. + :param style: If specified, the style overrides the other parameters. + :type style: :py:class:`dns.zone.ZoneStyle` or ``None`` """ if style is None: kw = {} @@ -715,8 +669,10 @@ class Zone(dns.transaction.TransactionManager): ) -> None: """Write a zone to a styled file. - *f*, a file or `str`. If *f* is a string, it is treated - as the name of a file to open. + :param style: The style to apply. + :type style: :py:class:`dns.zone.ZoneStyle` + :param f: A file object or a ``str`` filename. If a string, it is + treated as the name of a file to open. """ # Apply style items we learned from $UNICODE when we loaded the zone (if any). @@ -792,31 +748,23 @@ class Zone(dns.transaction.TransactionManager): ) -> str: """Return a zone's text as though it were written to a file. - *sorted*, a ``bool``. If True, the default, then the file - will be written with the names sorted in DNSSEC order from - least to greatest. Otherwise the names will be written in - whatever order they happen to have in the zone's dictionary. - - *relativize*, a ``bool``. If True, the default, then domain - names in the output will be relativized to the zone's origin - if possible. - - *nl*, a ``str`` or None. The end of line string. If not - ``None``, the output will use the platform's native - end-of-line marker (i.e. LF on POSIX, CRLF on Windows). - - *want_comments*, a ``bool``. If ``True``, emit end-of-line comments - as part of writing the file. If ``False``, the default, do not - emit them. - - *want_origin*, a ``bool``. If ``True``, emit a $ORIGIN line at - the start of the output. If ``False``, the default, do not emit - one. - - *style*, a :py:class:`dns.zone.ZoneStyle` or ``None`` (the default). If specified, - the style overrides the other parameters. - - Returns a ``str``. + :param bool sorted: If ``True`` (the default), the output will be + written with the names sorted in DNSSEC order from least to + greatest. Otherwise the names will be written in whatever order + they happen to have in the zone's dictionary. + :param bool relativize: If ``True`` (the default), domain names in + the output will be relativized to the zone's origin if possible. + :param nl: The end of line string. If ``None`` (the default), the + output will use the platform's native end-of-line marker (i.e. LF + on POSIX, CRLF on Windows). + :type nl: str or ``None`` + :param bool want_comments: If ``True``, emit end-of-line comments as + part of the output. If ``False`` (the default), do not emit them. + :param bool want_origin: If ``True``, emit a ``$ORIGIN`` line at the + start of the output. If ``False`` (the default), do not emit one. + :param style: If specified, the style overrides the other parameters. + :type style: :py:class:`dns.zone.ZoneStyle` or ``None`` + :rtype: str """ temp_buffer = io.StringIO() self.to_file(temp_buffer, sorted, relativize, nl, want_comments, want_origin) @@ -829,6 +777,10 @@ class Zone(dns.transaction.TransactionManager): See the documentation for :py:class:`dns.zone.ZoneStyle` for a description of the style parameters. + + :param style: The style to apply. + :type style: :py:class:`dns.zone.ZoneStyle` + :rtype: str """ temp_buffer = io.StringIO() @@ -840,11 +792,9 @@ class Zone(dns.transaction.TransactionManager): def check_origin(self) -> None: """Do some simple checking of the zone's origin. - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. + :raises dns.zone.NoSOA: if there is no SOA RRset. + :raises dns.zone.NoNS: if there is no NS RRset. + :raises KeyError: if there is no origin node. """ if self.relativize: name = dns.name.empty @@ -861,9 +811,8 @@ class Zone(dns.transaction.TransactionManager): ) -> dns.rdtypes.ANY.SOA.SOA: """Get the zone SOA rdata. - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Returns a ``dns.rdtypes.ANY.SOA.SOA`` Rdata. + :raises dns.zone.NoSOA: if there is no SOA RRset. + :rtype: :py:class:`dns.rdtypes.ANY.SOA.SOA` """ if self.relativize: origin_name = dns.name.empty @@ -1362,51 +1311,39 @@ def from_text( ) -> Zone: """Build a zone object from a zone file format string. - *text*, a ``str``, the zone file format input. - - *origin*, a ``dns.name.Name``, a ``str``, or ``None``. The origin - of the zone; if not specified, the first ``$ORIGIN`` statement in the - zone file will determine the origin of the zone. - - *rdclass*, a ``dns.rdataclass.RdataClass``, the zone's rdata class; the default is - class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - - *zone_factory*, the zone factory to use or ``None``. If ``None``, then - ``dns.zone.Zone`` will be used. The value may be any class or callable - that returns a subclass of ``dns.zone.Zone``. - - *filename*, a ``str`` or ``None``, the filename to emit when - describing where an error occurred; the default is ``''``. - - *allow_include*, a ``bool``. If ``True``, the default, then ``$INCLUDE`` - directives are permitted. If ``False``, then encoutering a ``$INCLUDE`` - will raise a ``SyntaxError`` exception. - - *check_origin*, a ``bool``. If ``True``, the default, then sanity - checks of the origin node will be made by calling the zone's - ``check_origin()`` method. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA encoder/decoder - is used. - - *allow_directives*, a ``bool`` or an iterable of `str`. If ``True``, the default, - then directives are permitted, and the *allow_include* parameter controls whether - ``$INCLUDE`` is permitted. If ``False`` or an empty iterable, then no directive - processing is done and any directive-like text will be treated as a regular owner - name. If a non-empty iterable, then only the listed directives (including the - ``$``) are allowed. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. - - Returns a subclass of ``dns.zone.Zone``. + :param str text: The zone file format input. + :param origin: The origin of the zone. If not specified, the first + ``$ORIGIN`` statement in the zone file will determine the origin. + :type origin: :py:class:`dns.name.Name`, str, or ``None`` + :param rdclass: The zone's rdata class; the default is class IN. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param bool relativize: Whether domain names are relativized to the + zone's origin. The default is ``True``. + :param zone_factory: The zone factory to use. If ``None``, then + :py:class:`dns.zone.Zone` will be used. The value may be any class + or callable that returns a subclass of :py:class:`dns.zone.Zone`. + :param filename: The filename to emit when describing where an error + occurred; the default is ``''``. + :type filename: str or ``None`` + :param bool allow_include: If ``True`` (the default), then ``$INCLUDE`` + directives are permitted. If ``False``, then encountering a + ``$INCLUDE`` will raise a :py:exc:`SyntaxError`. + :param bool check_origin: If ``True`` (the default), then sanity checks + of the origin node will be made by calling + :py:meth:`dns.zone.Zone.check_origin`. + :param idna_codec: The IDNA encoder/decoder. If ``None``, the default + IDNA encoder/decoder is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param allow_directives: If ``True`` (the default), directives are + permitted and *allow_include* controls ``$INCLUDE``. If ``False`` + or an empty iterable, no directive processing is done. If a + non-empty iterable, only the listed directives (including the ``$``) + are allowed. + :type allow_directives: bool or Iterable[str] + :raises dns.zone.NoSOA: if there is no SOA RRset. + :raises dns.zone.NoNS: if there is no NS RRset. + :raises KeyError: if there is no origin node. + :returns: A subclass of :py:class:`dns.zone.Zone`. """ return _from_text( text, @@ -1436,51 +1373,40 @@ def from_file( ) -> Zone: """Read a zone file and build a zone object. - *f*, a file or ``str``. If *f* is a string, it is treated - as the name of a file to open. - - *origin*, a ``dns.name.Name``, a ``str``, or ``None``. The origin - of the zone; if not specified, the first ``$ORIGIN`` statement in the - zone file will determine the origin of the zone. - - *rdclass*, an ``int``, the zone's rdata class; the default is class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - - *zone_factory*, the zone factory to use or ``None``. If ``None``, then - ``dns.zone.Zone`` will be used. The value may be any class or callable - that returns a subclass of ``dns.zone.Zone``. - - *filename*, a ``str`` or ``None``, the filename to emit when - describing where an error occurred; the default is ``''``. - - *allow_include*, a ``bool``. If ``True``, the default, then ``$INCLUDE`` - directives are permitted. If ``False``, then encoutering a ``$INCLUDE`` - will raise a ``SyntaxError`` exception. - - *check_origin*, a ``bool``. If ``True``, the default, then sanity - checks of the origin node will be made by calling the zone's - ``check_origin()`` method. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *allow_directives*, a ``bool`` or an iterable of `str`. If ``True``, the default, - then directives are permitted, and the *allow_include* parameter controls whether - ``$INCLUDE`` is permitted. If ``False`` or an empty iterable, then no directive - processing is done and any directive-like text will be treated as a regular owner - name. If a non-empty iterable, then only the listed directives (including the - ``$``) are allowed. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. - - Returns a subclass of ``dns.zone.Zone``. + :param f: A file object or a ``str`` filename. If a string, it is + treated as the name of a file to open. + :param origin: The origin of the zone. If not specified, the first + ``$ORIGIN`` statement in the zone file will determine the origin. + :type origin: :py:class:`dns.name.Name`, str, or ``None`` + :param rdclass: The zone's rdata class; the default is class IN. + :type rdclass: :py:class:`dns.rdataclass.RdataClass` + :param bool relativize: Whether domain names are relativized to the + zone's origin. The default is ``True``. + :param zone_factory: The zone factory to use. If ``None``, then + :py:class:`dns.zone.Zone` will be used. The value may be any class + or callable that returns a subclass of :py:class:`dns.zone.Zone`. + :param filename: The filename to emit when describing where an error + occurred; the default is ``''``. + :type filename: str or ``None`` + :param bool allow_include: If ``True`` (the default), then ``$INCLUDE`` + directives are permitted. If ``False``, then encountering a + ``$INCLUDE`` will raise a :py:exc:`SyntaxError`. + :param bool check_origin: If ``True`` (the default), then sanity checks + of the origin node will be made by calling + :py:meth:`dns.zone.Zone.check_origin`. + :param idna_codec: The IDNA encoder/decoder. If ``None``, the default + IDNA encoder/decoder is used. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param allow_directives: If ``True`` (the default), directives are + permitted and *allow_include* controls ``$INCLUDE``. If ``False`` + or an empty iterable, no directive processing is done. If a + non-empty iterable, only the listed directives (including the ``$``) + are allowed. + :type allow_directives: bool or Iterable[str] + :raises dns.zone.NoSOA: if there is no SOA RRset. + :raises dns.zone.NoNS: if there is no NS RRset. + :raises KeyError: if there is no origin node. + :returns: A subclass of :py:class:`dns.zone.Zone`. """ if isinstance(f, str): @@ -1513,27 +1439,21 @@ def from_xfr( ) -> Zone: """Convert the output of a zone transfer generator into a zone object. - *xfr*, a generator of ``dns.message.Message`` objects, typically - ``dns.query.xfr()``. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - It is essential that the relativize setting matches the one specified - to the generator. - - *check_origin*, a ``bool``. If ``True``, the default, then sanity - checks of the origin node will be made by calling the zone's - ``check_origin()`` method. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. - - Raises ``ValueError`` if no messages are yielded by the generator. - - Returns a subclass of ``dns.zone.Zone``. + :param xfr: A generator of :py:class:`dns.message.Message` objects, + typically from :py:func:`dns.query.xfr`. + :param zone_factory: The zone factory to use. If ``None``, then + :py:class:`dns.zone.Zone` will be used. + :param bool relativize: Whether domain names are relativized to the + zone's origin. The default is ``True``. It is essential that this + setting matches the one specified to the generator. + :param bool check_origin: If ``True`` (the default), then sanity checks + of the origin node will be made by calling + :py:meth:`dns.zone.Zone.check_origin`. + :raises dns.zone.NoSOA: if there is no SOA RRset. + :raises dns.zone.NoNS: if there is no NS RRset. + :raises KeyError: if there is no origin node. + :raises ValueError: if no messages are yielded by the generator. + :returns: A subclass of :py:class:`dns.zone.Zone`. """ z = None diff --git a/dns/zonefile.py b/dns/zonefile.py index ce7ec765..113cc3d7 100644 --- a/dns/zonefile.py +++ b/dns/zonefile.py @@ -461,8 +461,8 @@ class Reader: def read(self) -> None: """Read a DNS zone file and build a zone object. - @raises dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises dns.zone.NoNS: No NS RRset was found at the zone origin + :raises dns.zone.NoSOA: if there is no SOA RR at the zone origin. + :raises dns.zone.NoNS: if there is no NS RRset at the zone origin. """ try: @@ -687,51 +687,42 @@ def read_rrsets( """Read one or more rrsets from the specified text, possibly subject to restrictions. - *text*, a file object or a string, is the input to process. - - *name*, a string, ``dns.name.Name``, or ``None``, is the owner name of - the rrset. If not ``None``, then the owner name is "forced", and the - input must not specify an owner name. If ``None``, then any owner names - are allowed and must be present in the input. - - *ttl*, an ``int``, string, or None. If not ``None``, the the TTL is - forced to be the specified value and the input must not specify a TTL. - If ``None``, then a TTL may be specified in the input. If it is not - specified, then the *default_ttl* will be used. - - *rdclass*, a ``dns.rdataclass.RdataClass``, string, or ``None``. If - not ``None``, then the class is forced to the specified value, and the - input must not specify a class. If ``None``, then the input may specify - a class that matches *default_rdclass*. Note that it is not possible to - return rrsets with differing classes; specifying ``None`` for the class - simply allows the user to optionally type a class as that may be convenient - when cutting and pasting. - - *default_rdclass*, a ``dns.rdataclass.RdataClass`` or string. The class - of the returned rrsets. - - *rdtype*, a ``dns.rdatatype.RdataType``, string, or ``None``. If not - ``None``, then the type is forced to the specified value, and the - input must not specify a type. If ``None``, then a type must be present - for each RR. - - *default_ttl*, an ``int``, string, or ``None``. If not ``None``, then if - the TTL is not forced and is not specified, then this value will be used. - if ``None``, then if the TTL is not forced an error will occur if the TTL - is not specified. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. Note that codecs only apply to the owner name; dnspython does - not do IDNA for names in rdata, as there is no IDNA zonefile format. - - *origin*, a string, ``dns.name.Name``, or ``None``, is the origin for any - relative names in the input, and also the origin to relativize to if - *relativize* is ``True``. - - *relativize*, a bool. If ``True``, names are relativized to the *origin*; - if ``False`` then any relative names in the input are made absolute by - appending the *origin*. + :param text: The input to process, either a file object or a string. + :param name: The owner name of the rrset. If not ``None``, the owner + name is forced and the input must not specify one. If ``None``, + any owner names are allowed and must be present in the input. + :type name: str, :py:class:`dns.name.Name`, or ``None`` + :param ttl: If not ``None``, the TTL is forced to the specified value + and the input must not specify a TTL. If ``None``, a TTL may be + specified in the input; if not specified, *default_ttl* will be used. + :type ttl: int, str, or ``None`` + :param rdclass: If not ``None``, the class is forced to the specified + value and the input must not specify a class. If ``None``, the input + may optionally specify a class matching *default_rdclass*. Note that + rrsets with differing classes cannot be returned; ``None`` here simply + allows the user to optionally write a class in the input. + :type rdclass: :py:class:`dns.rdataclass.RdataClass`, str, or ``None`` + :param default_rdclass: The class of the returned rrsets. + :type default_rdclass: :py:class:`dns.rdataclass.RdataClass` or str + :param rdtype: If not ``None``, the type is forced to the specified value + and the input must not specify a type. If ``None``, a type must be + present for each RR. + :type rdtype: :py:class:`dns.rdatatype.RdataType`, str, or ``None`` + :param default_ttl: If not ``None``, and the TTL is not forced and not + specified in the input, this value will be used. If ``None``, an + error will occur if the TTL is not forced and not specified. + :type default_ttl: int, str, or ``None`` + :param idna_codec: The IDNA encoder/decoder. If ``None``, the default + IDNA encoder/decoder is used. Note that codecs only apply to the + owner name; dnspython does not do IDNA for names in rdata. + :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` + :param origin: The origin for any relative names in the input, and also + the origin to relativize to if *relativize* is ``True``. + :type origin: str, :py:class:`dns.name.Name`, or ``None`` + :param bool relativize: If ``True``, names are relativized to *origin*; + if ``False``, relative names in the input are made absolute by + appending *origin*. + :rtype: list[:py:class:`dns.rrset.RRset`] """ if isinstance(origin, str): origin = dns.name.from_text(origin, dns.name.root, idna_codec) diff --git a/doc/Makefile b/doc/Makefile index aad55329..c8233eb6 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -17,4 +17,5 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile + rm -rf _build @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) -n $(O) diff --git a/doc/async-backend.rst b/doc/async-backend.rst index 46caa4e4..edd8d80f 100644 --- a/doc/async-backend.rst +++ b/doc/async-backend.rst @@ -12,6 +12,15 @@ Dnspython attempts to determine which backend is in use by "sniffing" for it with the ``sniffio`` module if it is installed. If sniffio is not available, dnspython will try to detect asyncio directly. +.. autoclass:: dns.asyncbackend.Backend + :members: + +.. autoclass:: dns.asyncbackend.DatagramSocket + :members: + +.. autoclass:: dns.asyncbackend.StreamSocket + :members: + .. autofunction:: dns.asyncbackend.get_default_backend .. autofunction:: dns.asyncbackend.set_default_backend .. autofunction:: dns.asyncbackend.sniff diff --git a/doc/async-query.rst b/doc/async-query.rst index dc226923..b94598b8 100644 --- a/doc/async-query.rst +++ b/doc/async-query.rst @@ -4,9 +4,9 @@ DNS Query Support ================= -The ``dns.asyncquery`` module is for sending messages to DNS servers, and +The :py:mod:`dns.asyncquery` module is for sending messages to DNS servers, and processing their responses. If you want "stub resolver" behavior, then -you should use the higher level ``dns.asyncresolver`` module; see +you should use the higher level :py:mod:`dns.asyncresolver` module; see :ref:`async_resolver`. For UDP and TCP, the module provides a single "do everything" query diff --git a/doc/async-resolver-class.rst b/doc/async-resolver-class.rst index 9cf39a31..b79a4f5b 100644 --- a/doc/async-resolver-class.rst +++ b/doc/async-resolver-class.rst @@ -3,7 +3,7 @@ The dns.asyncresolver.Resolver Class ------------------------------------ -The async resolver is a subclass of ``dns.resolver.Resolver`` and has the +The async resolver is a subclass of :py:class:`dns.resolver.Resolver` and has the same attributes. The methods are similar, but I/O methods like ``resolve()`` are asynchronous. diff --git a/doc/async.rst b/doc/async.rst index 3c7afecd..d9005905 100644 --- a/doc/async.rst +++ b/doc/async.rst @@ -3,9 +3,9 @@ Asynchronous I/O Support ======================== -The ``dns.asyncquery`` and ``dns.asyncresolver`` modules offer -asynchronous APIs equivalent to those of ``dns.query`` and -``dns.resolver``. +The :py:mod:`dns.asyncquery` and :py:mod:`dns.asyncresolver` modules offer +asynchronous APIs equivalent to those of :py:mod:`dns.query` and +:py:mod:`dns.resolver`. Dnspython presents a uniform API, but offers two different backend implementations, to support the Trio and asyncio libraries. diff --git a/doc/conf.py b/doc/conf.py index 5c91dcb6..075550d3 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -34,11 +34,44 @@ sys.path.insert(0, os.path.abspath("..")) # ones. extensions = [ "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", "sphinx.ext.viewcode", "sphinx.ext.githubpages", "sphinx.ext.todo", ] +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "cryptography": ("https://cryptography.io/en/latest/", None) +} + +nitpick_ignore = [ + ("py:class", "dns.tokenizer.Tokenizer"), + ("py:class", "dns.wirebase.Parser"), + ("py:class", "dns.wire.Parser"), + ("py:class", "dns.btree.BTreeDict"), + ("py:class", "dns.btree.BTree"), + # Private async backend classes (underscore-prefixed, not publicly documented) + ("py:class", "dns._asyncbackend.Backend"), + ("py:class", "dns._asyncbackend.DatagramSocket"), + ("py:class", "dns._asyncbackend.StreamSocket"), + # TSIG module not yet documented + ("py:class", "dns.tsig.Key"), + ("py:class", "dns.tsig.HMACTSig"), + ("py:class", "dns.tsig.GSSTSig"), + # Malformed dict[] type annotation cross-ref from autodoc + ("py:class", "dict[~dns.name.Name"), + # Public async backend module classes (implementation detail) + ("py:class", "dns.asyncbackend.Backend"), + # Python built-in file object (old-style type annotation) + ("py:class", "file"), + # socket module class (from dns.query sock parameters) + ("py:class", "socket"), + # External libraries not in intersphinx + ("py:class", "httpx.AsyncClient"), + ("py:class", "dns.quic.AsyncQuicConnection"), +] + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] diff --git a/doc/dnssec.rst b/doc/dnssec.rst index 06392bc3..baf9e4d5 100644 --- a/doc/dnssec.rst +++ b/doc/dnssec.rst @@ -28,8 +28,32 @@ DNSSEC Functions .. autofunction:: dns.dnssec.default_rrset_signer() .. autofunction:: dns.dnssec.sign_zone() -DNSSEC Algorithms ------------------ +DNSSEC Policy +------------- + +.. autoclass:: dns.dnssec.Policy + :members: + +DNSSEC Algorithm Types +---------------------- + +.. autoclass:: dns.dnssectypes.Algorithm + :members: + +.. autoclass:: dns.dnssectypes.DSDigest + :members: + +DNSSEC Algorithm Implementations +--------------------------------- + +.. autoclass:: dns.dnssecalgs.base.GenericPublicKey + :members: + +.. autoclass:: dns.dnssecalgs.base.GenericPrivateKey + :members: + +DNSSEC Algorithm Constants +--------------------------- .. autodata:: dns.dnssec.RSAMD5 .. autodata:: dns.dnssec.DH diff --git a/doc/inbound-xfr-class.rst b/doc/inbound-xfr-class.rst index c5b747f9..78c1c9c3 100644 --- a/doc/inbound-xfr-class.rst +++ b/doc/inbound-xfr-class.rst @@ -14,6 +14,8 @@ The ``make_query()`` function is used to making the query message for the query methods to use in more complex situations, e.g. with TSIG or EDNS. +.. autoexception:: dns.xfr.UseTCP + .. autoclass:: dns.xfr.Inbound :members: diff --git a/doc/message-class.rst b/doc/message-class.rst index 8f2731df..580dac7a 100644 --- a/doc/message-class.rst +++ b/doc/message-class.rst @@ -19,7 +19,7 @@ DNS opcodes that do not have a more specific class. .. attribute:: sections - A list of lists of ``dns.rrset.RRset`` objects. + A list of lists of :py:class:`dns.rrset.RRset` objects. .. attribute:: edns @@ -35,7 +35,7 @@ DNS opcodes that do not have a more specific class. .. attribute:: options - The EDNS options, a list of ``dns.edns.Option`` objects. The default + The EDNS options, a list of :py:class:`dns.edns.Option` objects. The default is the empty list. .. attribute:: request_payload @@ -51,11 +51,11 @@ DNS opcodes that do not have a more specific class. .. attribute:: keyname - The TSIG keyname to use, a ``dns.name.Name``. The default is ``None``. + The TSIG keyname to use, a :py:class:`dns.name.Name`. The default is ``None``. .. attribute:: keyalgorithm - A ``dns.name.Name``, the TSIG algorithm to use. Defaults to + A :py:class:`dns.name.Name`, the TSIG algorithm to use. Defaults to ``dns.tsig.default_algorithm``. Constants for TSIG algorithms are defined the in ``dns.tsig`` module. @@ -92,7 +92,7 @@ DNS opcodes that do not have a more specific class. .. attribute:: origin - A ``dns.name.Name``. The origin of the zone in messages which are + A :py:class:`dns.name.Name`. The origin of the zone in messages which are used for zone transfers or for DNS dynamic updates. The default is ``None``. @@ -130,7 +130,7 @@ DNS opcodes that do not have a more specific class. .. attribute:: wire A ``bytes`` or ``None``, the encoded wire format data used to create this - message with ``dns.message.from_wire()`` or the output most recently generated by + message with :py:func:`dns.message.from_wire` or the output most recently generated by ``to_wire()``. .. autoclass:: dns.message.MessageStyle diff --git a/doc/message-edns.rst b/doc/message-edns.rst index 8424fa13..a21d0e83 100644 --- a/doc/message-edns.rst +++ b/doc/message-edns.rst @@ -7,7 +7,7 @@ EDNS allows for larger messages and also provides an extension mechanism for the protocol. EDNS *options* are typed data, and are treated much like Rdata. For example, if dnspython encounters the EDNS ``ECS`` option code when parsing a DNS wire format message, it -will create a ``dns.edns.ECSOption`` object to represent it. +will create a :py:class:`dns.edns.ECSOption` object to represent it. .. autoclass:: dns.edns.OptionType diff --git a/doc/message-make.rst b/doc/message-make.rst index 3c580a94..fd6ad36a 100644 --- a/doc/message-make.rst +++ b/doc/message-make.rst @@ -3,6 +3,11 @@ Making DNS Messages ------------------- +.. autoexception:: dns.message.Truncated + +.. autoclass:: dns.message.CopyMode + :members: + .. autofunction:: dns.message.from_file .. autofunction:: dns.message.from_text .. autofunction:: dns.message.from_wire diff --git a/doc/message-opcode.rst b/doc/message-opcode.rst index ad931e89..334ad3da 100644 --- a/doc/message-opcode.rst +++ b/doc/message-opcode.rst @@ -7,6 +7,9 @@ DNS Opcodes describe what kind of operation a DNS message is requesting or replying to. Opcodes are embedded in the flags field in the DNS header. +.. autoclass:: dns.opcode.Opcode + :members: + .. autodata:: dns.opcode.QUERY .. autodata:: dns.opcode.IQUERY .. autodata:: dns.opcode.STATUS diff --git a/doc/message-query.rst b/doc/message-query.rst index 03c50318..1010b675 100644 --- a/doc/message-query.rst +++ b/doc/message-query.rst @@ -3,7 +3,11 @@ The dns.message.QueryMessage Class ---------------------------------- -The ``dns.message.QueryMessage`` class is used for ordinary DNS query messages. +.. autoexception:: dns.message.NotQueryResponse +.. autoexception:: dns.message.ChainTooLong +.. autoexception:: dns.message.AnswerForNXDOMAIN + +The :py:class:`dns.message.QueryMessage` class is used for ordinary DNS query messages. .. autoclass:: dns.message.QueryMessage :members: @@ -11,8 +15,8 @@ The ``dns.message.QueryMessage`` class is used for ordinary DNS query messages. The dns.message.ChainingResult Class ------------------------------------ -Objects of the ``dns.message.ChainingResult`` class are returned by the -``dns.message.QueryMessage.resolve_chaining()`` method. +Objects of the :py:class:`dns.message.ChainingResult` class are returned by the +:py:meth:`dns.message.QueryMessage.resolve_chaining` method. .. autoclass:: dns.message.ChainingResult :members: diff --git a/doc/message-rcode.rst b/doc/message-rcode.rst index 6dd1bb43..f64ebd18 100644 --- a/doc/message-rcode.rst +++ b/doc/message-rcode.rst @@ -8,6 +8,9 @@ use, then the rcode is encoded solely in the DNS header. If EDNS is in use, then the rcode is encoded using bits form both the header and the EDNS OPT RR. +.. autoclass:: dns.rcode.Rcode + :members: + .. autodata:: dns.rcode.NOERROR .. autodata:: dns.rcode.FORMERR .. autodata:: dns.rcode.SERVFAIL diff --git a/doc/message-update.rst b/doc/message-update.rst index 87e21718..da867f9d 100644 --- a/doc/message-update.rst +++ b/doc/message-update.rst @@ -3,7 +3,7 @@ The dns.update.UpdateMessage Class ---------------------------------- -The ``dns.update.UpdateMessage`` class is used for DNS Dynamic Update +The :py:class:`dns.update.UpdateMessage` class is used for DNS Dynamic Update messages. It provides section access using the DNS Dynamic Update section names, and a variety of convenience methods for constructing dynamic updates. diff --git a/doc/message.rst b/doc/message.rst index ca5a209c..3f3b9f1d 100644 --- a/doc/message.rst +++ b/doc/message.rst @@ -4,7 +4,7 @@ DNS Messages ============ -Objects of the dns.message.Message class and its subclasses represent +Objects of the :py:class:`dns.message.Message` class and its subclasses represent a single DNS message, as defined by `RFC 1035 `_ and its many updates and extensions. diff --git a/doc/name-class.rst b/doc/name-class.rst index acae087e..7e792c07 100644 --- a/doc/name-class.rst +++ b/doc/name-class.rst @@ -6,6 +6,7 @@ The dns.name.Name Class and Predefined Names .. autoclass:: dns.name.Name :members: :inherited-members: + :special-members: __init__ .. attribute:: labels @@ -13,9 +14,7 @@ The dns.name.Name Class and Predefined Names labels in the name, in order from least-significant label (i.e. farthest from the origin) to most-significant label. - .. method:: __init__(labels) - - Initialize a name using *labels*, an iterable of ``bytes`` or ``str``. + :type: tuple[bytes, ...] .. data:: dns.name.root diff --git a/doc/name-codecs.rst b/doc/name-codecs.rst index d93acafc..0a2f3e79 100644 --- a/doc/name-codecs.rst +++ b/doc/name-codecs.rst @@ -17,9 +17,9 @@ Dnspython provides "codecs" to implement International Domain Name policy according to the user's desire. The default codec to use for all of dnspython can be set by calling -py:func:`dns.name.set_default_idna_codec()`. The default default codec is -``dns.name.IDNA_2008_Practical`` if the ``idna`` module is installed, and -``dns.name.IDNA_2003_Practical`` otherwise. +:py:func:`dns.name.set_default_idna_codec`. The default default codec is +:py:data:`dns.name.IDNA_2008_Practical` if the ``idna`` module is installed, and +:py:data:`dns.name.IDNA_2003_Practical` otherwise. .. autoclass:: dns.name.IDNACodec :members: @@ -40,7 +40,7 @@ py:func:`dns.name.set_default_idna_codec()`. The default default codec is .. data:: dns.name.IDNA_2003 - A synonym for ``dns.name.IDNA_2003_Practical``. + A synonym for :py:data:`dns.name.IDNA_2003_Practical`. .. data:: dns.name.IDNA_2008_Practical @@ -64,13 +64,13 @@ py:func:`dns.name.set_default_idna_codec()`. The default default codec is The "UTS 46" codec encodes using IDNA 2008 rules with UTS 46 compatibility processing in the "transitional mode" and decodes punycode without checking for IDNA 2008 compliance. This codec - is the same as ``dns.name.IDNA_2008_UTS_46`` in idna 3.11 and + is the same as :py:data:`dns.name.IDNA_2008_UTS_46` in idna 3.11 and later as transitional support has been removed. .. data:: dns.name.IDNA_2008 - A synonym for ``dns.name.IDNA_2008_Practical``. + A synonym for :py:data:`dns.name.IDNA_2008_Practical`. .. data:: dns.name.IDNA_DEFAULT diff --git a/doc/name.rst b/doc/name.rst index 414db1c0..0ff104c8 100644 --- a/doc/name.rst +++ b/doc/name.rst @@ -4,7 +4,7 @@ DNS Names ========= -Objects of the dns.name.Name class represent an immutable domain name. +Objects of the :py:class:`dns.name.Name` class represent an immutable domain name. The representation is a tuple of labels, with each label being a ``bytes`` object in the DNS wire format. Typically names are not created by supplying the labels tuple directly, but rather by converting from DNS @@ -22,7 +22,7 @@ and absolute names, other than in the context of a zone. Names encoded in the DNS wire protocol are always absolute. Dnspython's functions to make names from text also default to an origin of the root name, and thus to make a relative name using them you must specify an origin of None or -``dns.name.empty``. +:py:data:`dns.name.empty`. Names are compared and ordered according to the rules of the DNS. The order is the DNSSEC canonical ordering. Relative names always sort before diff --git a/doc/query.rst b/doc/query.rst index 0fe3ccb6..d84eeeec 100644 --- a/doc/query.rst +++ b/doc/query.rst @@ -4,9 +4,9 @@ DNS Query Support ================= -The ``dns.query`` module is for sending messages to DNS servers, and +The :py:mod:`dns.query` module is for sending messages to DNS servers, and processing their responses. If you want "stub resolver" behavior, then -you should use the higher level ``dns.resolver`` module; see :ref:`resolver`. +you should use the higher level :py:mod:`dns.resolver` module; see :ref:`resolver`. For UDP and TCP, the module provides a single "do everything" query function, and also provides the send and receive halves of this function @@ -44,6 +44,9 @@ Zone Transfers As of dnspython 2.1, :py:func:`dns.query.xfr` is deprecated. Please use :py:func:`dns.query.inbound_xfr` instead. +.. autoclass:: dns.query.HTTPVersion + :members: + .. autoclass:: dns.query.UDPMode .. autofunction:: dns.query.inbound_xfr diff --git a/doc/rdata-class.rst b/doc/rdata-class.rst index 82d61cfe..6299693c 100644 --- a/doc/rdata-class.rst +++ b/doc/rdata-class.rst @@ -5,12 +5,12 @@ ====================== All Rdata objects are instances of some subclass of -``dns.rdata.Rdata``, and are immutable. The Rdata factory functions +:py:class:`dns.rdata.Rdata`, and are immutable. The Rdata factory functions described in :ref:`rdata-make` will create objects which are instances of the most appropriate subclass. For example, a AAAA record will be -an instance of the ``dns.rdtypes.IN.AAAA`` class, but a record of +an instance of the :py:class:`dns.rdtypes.IN.AAAA.AAAA` class, but a record of TYPE12345, which we don't know anything specific about, will be an -instance of ``dns.rdata.GenericRdata``. +instance of :py:class:`dns.rdata.GenericRdata`. Rdata of the same type and class are ordered. For rdata that do not contain domain names, or which contain absolute domain names, the diff --git a/doc/rdata-set-classes.rst b/doc/rdata-set-classes.rst index d2963cc9..6c73df7a 100644 --- a/doc/rdata-set-classes.rst +++ b/doc/rdata-set-classes.rst @@ -9,7 +9,7 @@ rdatatype, rdataclass, and covered type. ``Rdatasets`` also have a set API, but are also ordered. An ``RRset`` is a subclass of ``Rdataset`` that also has an owner -name, i.e. a ``dns.name.Name`` that says where in the DNS tree this +name, i.e. a :py:class:`dns.name.Name` that says where in the DNS tree this set is located. A ``Node`` is a set of ``Rdataset`` objects, the Rdatasets being @@ -29,6 +29,9 @@ tree. Nodes are primarily used in ``Zone`` objects. .. autoclass:: dns.node.Node :members: +.. autoclass:: dns.node.ImmutableNode + :members: + .. autoclass:: dns.node.NodeKind :members: diff --git a/doc/rdata-subclasses.rst b/doc/rdata-subclasses.rst index aac3749f..efd91fe4 100644 --- a/doc/rdata-subclasses.rst +++ b/doc/rdata-subclasses.rst @@ -17,24 +17,27 @@ Universal Types .. autoclass:: dns.rdtypes.ANY.AFSDB.AFSDB :members: +.. autoclass:: dns.rdtypes.ANY.AMTRELAY.Relay + :members: + .. autoclass:: dns.rdtypes.ANY.AMTRELAY.AMTRELAY :members: .. attribute:: precedence - An ``int``, the 8-bit unsigned integer preference. + An ``int``, the 8-bit unsigned integer preference. .. attribute:: discovery_optional - A ``bool``, specifying whether discovery is optional or not. + A ``bool``, specifying whether discovery is optional or not. .. attribute:: relay_type - An ``int``, the 8-bit unsigned integer relay type. + An ``int``, the 8-bit unsigned integer relay type. .. attribute:: relay - A ``dns.rdtypes.ANY.AMTRELAY.Relay`` instance, the relay. + A :py:class:`dns.rdtypes.ANY.AMTRELAY.Relay` instance, the relay. .. autoclass:: dns.rdtypes.ANY.AVC.AVC :members: @@ -120,7 +123,7 @@ Universal Types .. attribute:: target - A ``dns.name.Name``, the target name. + A :py:class:`dns.name.Name`, the target name. .. autoclass:: dns.rdtypes.ANY.CSYNC.CSYNC :members: @@ -161,7 +164,7 @@ Universal Types .. attribute:: target - A ``dns.name.Name``, the target name. + A :py:class:`dns.name.Name`, the target name. .. autoclass:: dns.rdtypes.ANY.DNSKEY.DNSKEY :members: @@ -201,16 +204,19 @@ Universal Types A ``bytes``, the digest of the key. +.. autoclass:: dns.rdtypes.ANY.DSYNC.Scheme + :members: + .. autoclass:: dns.rdtypes.ANY.DSYNC.DSYNC :members: .. attribute:: rrtype - A ``dns.rdatatype.RdataType``, the type this DSYNC record will notify about. + A :py:class:`dns.rdatatype.RdataType`, the type this DSYNC record will notify about. .. attribute:: scheme - A ``dns.rdtypes.ANY.DSYNC.Scheme`` the scheme to use, typically + A :py:class:`dns.rdtypes.ANY.DSYNC.Scheme` the scheme to use, typically ``dns.rdtypes.ANY.DSYNC.Scheme.NOTIFY``. .. attribute:: port @@ -219,7 +225,7 @@ Universal Types .. attribute:: target - A ``dns.name.Name``, the hostname of the notification receiver. + A :py:class:`dns.name.Name`, the hostname of the notification receiver. .. autoclass:: dns.rdtypes.ANY.EUI48.EUI48 :members: @@ -278,7 +284,7 @@ Universal Types .. attribute:: servers - A tuple of ``dns.name.Name`` objects, the rendezvous servers. + A tuple of :py:class:`dns.name.Name` objects, the rendezvous servers. .. autoclass:: dns.rdtypes.ANY.ISDN.ISDN :members: @@ -351,7 +357,7 @@ Universal Types .. attribute:: fqdn - A ``dns.name.Name``, the domain name of a locator. + A :py:class:`dns.name.Name`, the domain name of a locator. .. autoclass:: dns.rdtypes.ANY.MX.MX :members: @@ -362,7 +368,7 @@ Universal Types .. attribute:: exchange - A ``dns.name.Name``, the exchange name. + A :py:class:`dns.name.Name`, the exchange name. .. autoclass:: dns.rdtypes.ANY.NID.NID :members: @@ -386,14 +392,14 @@ Universal Types .. attribute:: target - A ``dns.name.Name``, the target name. + A :py:class:`dns.name.Name`, the target name. .. autoclass:: dns.rdtypes.ANY.NSEC.NSEC :members: .. attribute:: next - A ``dns.name.Name``, the next name + A :py:class:`dns.name.Name`, the next name .. attribute:: windows @@ -457,7 +463,7 @@ Universal Types .. attribute:: target - A ``dns.name.Name``, the target name. + A :py:class:`dns.name.Name`, the target name. .. autoclass:: dns.rdtypes.ANY.RESINFO.RESINFO :members: @@ -471,11 +477,11 @@ Universal Types .. attribute:: mbox - A ``dns.name.Name``, the responsible person's mailbox. + A :py:class:`dns.name.Name`, the responsible person's mailbox. .. attribute:: txt - A ``dns.name.Name``, the owner name of a node with TXT records, + A :py:class:`dns.name.Name`, the owner name of a node with TXT records, or the root name if no TXT records are associated with this RP. .. autoclass:: dns.rdtypes.ANY.RRSIG.RRSIG @@ -511,7 +517,7 @@ Universal Types .. attribute:: signer - A ``dns.name.Name``, the signer. + A :py:class:`dns.name.Name`, the signer. .. attribute:: signature @@ -526,7 +532,7 @@ Universal Types .. attribute:: exchange - A ``dns.name.Name``, the exchange name. + A :py:class:`dns.name.Name`, the exchange name. .. autoclass:: dns.rdtypes.ANY.SMIMEA.SMIMEA :members: @@ -552,11 +558,11 @@ Universal Types .. attribute:: mname - A ``dns.name.Name``, the MNAME (master name). + A :py:class:`dns.name.Name`, the MNAME (master name). .. attribute:: rname - A ``dns.name.Name``, the RNAME (responsible name). + A :py:class:`dns.name.Name`, the RNAME (responsible name). .. attribute:: serial @@ -640,7 +646,7 @@ Universal Types .. attribute:: target - A ``dns.name.Name``, the target. + A :py:class:`dns.name.Name`, the target. .. autoclass:: dns.rdtypes.ANY.WALLET.WALLET :members: @@ -699,7 +705,7 @@ Types specific to class IN .. attribute:: items - A tuple of ``dns.rdtypes.IN.APL.APLItem``. + A tuple of :py:class:`dns.rdtypes.IN.APL.APLItem`. .. autoclass:: dns.rdtypes.IN.DHCID.DHCID :members: @@ -718,11 +724,11 @@ Types specific to class IN .. attribute:: target - A ``dns.name.Name``, the target name. + A :py:class:`dns.name.Name`, the target name. .. attribute:: params - A ``dict[dns.rdtypes.svcbbase.ParamKey, dns.rdtypes.svcbbase.Param]``, the + A dict mapping :py:class:`dns.rdtypes.svcbbase.ParamKey` to :py:class:`dns.rdtypes.svcbbase.Param`, the parameters. See the dedicated section :ref:`svcb-https-params` below for more information on the parameter types. @@ -747,8 +753,8 @@ Types specific to class IN .. attribute:: gateway - The gateway. This value may be ``None``, a ``str` with an IPv4 or - IPV6 address, or a ``dns.name.Name``. + The gateway. This value may be ``None``, a ``str`` with an IPv4 or + IPV6 address, or a :py:class:`dns.name.Name`. .. attribute:: key @@ -763,7 +769,7 @@ Types specific to class IN .. attribute:: exchange - A ``dns.name.Name``, the exchange name. + A :py:class:`dns.name.Name`, the exchange name. .. autoclass:: dns.rdtypes.IN.NAPTR.NAPTR :members: @@ -790,7 +796,7 @@ Types specific to class IN .. attribute:: replacement - A ``dns.name.Name``, the replacement name. + A :py:class:`dns.name.Name`, the replacement name. .. autoclass:: dns.rdtypes.IN.NSAP.NSAP :members: @@ -804,7 +810,7 @@ Types specific to class IN .. attribute:: target - A ``dns.name.Name``, the target name. + A :py:class:`dns.name.Name`, the target name. .. autoclass:: dns.rdtypes.IN.PX.PX :members: @@ -815,11 +821,11 @@ Types specific to class IN .. attribute:: map822 - A ``dns.name.Name``, the map822 name. + A :py:class:`dns.name.Name`, the map822 name. .. attribute:: mapx400 - A ``dns.name.Name``, the mapx400 name. + A :py:class:`dns.name.Name`, the mapx400 name. .. autoclass:: dns.rdtypes.IN.SRV.SRV :members: @@ -838,7 +844,7 @@ Types specific to class IN .. attribute:: target - A ``dns.name.Name``, the target host. + A :py:class:`dns.name.Name`, the target host. .. autoclass:: dns.rdtypes.IN.SVCB.SVCB :members: @@ -849,11 +855,11 @@ Types specific to class IN .. attribute:: target - A ``dns.name.Name``, the target name. + A :py:class:`dns.name.Name`, the target name. .. attribute:: params - A ``dict[dns.rdtypes.svcbbase.ParamKey, dns.rdtypes.svcbbase.Param]``, the + A dict mapping :py:class:`dns.rdtypes.svcbbase.ParamKey` to :py:class:`dns.rdtypes.svcbbase.Param`, the parameters. See the dedicated section :ref:`svcb-https-params` below for more information on the parameter types. @@ -903,7 +909,7 @@ SVCB and HTTPS Parameter Classes .. attribute:: keys - A tuple of ``ParamKey``, the keys which are mandatory. + A tuple of :py:class:`dns.rdtypes.svcbbase.ParamKey`, the keys which are mandatory. .. autoclass:: dns.rdtypes.svcbbase.ALPNParam :members: diff --git a/doc/rdata-types.rst b/doc/rdata-types.rst index 47ec07bd..bdc4ca0a 100644 --- a/doc/rdata-types.rst +++ b/doc/rdata-types.rst @@ -8,8 +8,8 @@ datum is called an *rdata*. The type of an rdata is specified by its *rdataclass* and *rdatatype*. The class is almost always `IN`, the Internet class, and may often be omitted in the dnspython APIs. -The ``dns.rdataclass`` module provides constants for each defined -rdata class, as well as some helpful functions. The ``dns.rdatatype`` +The :py:mod:`dns.rdataclass` module provides constants for each defined +rdata class, as well as some helpful functions. The :py:mod:`dns.rdatatype` module does the same for rdata types. Examples of the constants are:: dns.rdataclass.IN diff --git a/doc/rdatatype-list.rst b/doc/rdatatype-list.rst index 20c4b06e..f64530f0 100644 --- a/doc/rdatatype-list.rst +++ b/doc/rdatatype-list.rst @@ -97,6 +97,8 @@ Rdatatypes :annotation: = 104 .. py:data:: dns.rdatatype.NINFO :annotation: = 56 +.. py:data:: dns.rdatatype.NONE + :annotation: = 0 .. py:data:: dns.rdatatype.NS :annotation: = 2 .. py:data:: dns.rdatatype.NSAP @@ -111,6 +113,8 @@ Rdatatypes :annotation: = 51 .. py:data:: dns.rdatatype.NULL :annotation: = 10 +.. py:data:: dns.rdatatype.NXNAME + :annotation: = 128 .. py:data:: dns.rdatatype.NXT :annotation: = 30 .. py:data:: dns.rdatatype.OPENPGPKEY diff --git a/doc/resolver-class.rst b/doc/resolver-class.rst index fdff7747..09716985 100644 --- a/doc/resolver-class.rst +++ b/doc/resolver-class.rst @@ -8,20 +8,20 @@ The dns.resolver.Resolver and dns.resolver.Answer Classes .. attribute:: domain - A ``dns.name.Name``, the domain of this host. + A :py:class:`dns.name.Name`, the domain of this host. .. attribute:: nameservers - A ``list`` of ``str`` or ``dns.nameserver.Nameserver``. A string may be + A ``list`` of ``str`` or :py:class:`dns.nameserver.Nameserver`. A string may be an IPv4 or IPv6 address, or an https URL. This field is actually a property, and returns a tuple as of dnspython 2.4. Assigning this field converts any strings into - ``dns.nameserver.Nameserver`` instances. + :py:class:`dns.nameserver.Nameserver` instances. .. attribute:: search - A ``list`` of dns.name.Name objects. If the query name is a + A ``list`` of :py:class:`dns.name.Name` objects. If the query name is a relative name, the resolver will construct absolute query names to try by appending values from the search list. @@ -53,12 +53,12 @@ The dns.resolver.Resolver and dns.resolver.Answer Classes A ``float``, the number of seconds to spend trying to get an answer to the question. If the lifetime expires a - ``dns.exception.Timeout`` exception will be raised. + :py:exc:`dns.exception.Timeout` exception will be raised. .. attribute:: cache An object implementing the caching protocol, e.g. a - ``dns.resolver.Cache`` or a ``dns.resolver.LRUCache``. The default + :py:class:`dns.resolver.Cache` or a :py:class:`dns.resolver.LRUCache`. The default is ``None``, in which case there is no local caching. .. attribute:: retry_servfail @@ -77,13 +77,13 @@ The dns.resolver.Resolver and dns.resolver.Answer Classes .. attribute:: keyname - A ``dns.name.Name`` or ``None``, the name of the TSIG key to + A :py:class:`dns.name.Name` or ``None``, the name of the TSIG key to use; defaults to ``None``. The key must be defined in the keyring. .. attribute:: keyalgorithm - A ``dns.name.Name`` or ``str``, the TSIG algorithm to use. + A :py:class:`dns.name.Name` or ``str``, the TSIG algorithm to use. .. attribute:: edns @@ -105,16 +105,19 @@ The dns.resolver.Resolver and dns.resolver.Answer Classes .. attribute:: flags An ``int`` or ``None``, the message flags to use. If ``None``, - then the default flags as set by the ``dns.message.Message`` + then the default flags as set by the :py:class:`dns.message.Message` constructor will be used. +.. autoclass:: dns.resolver.HostAnswers + :members: + .. autoclass:: dns.resolver.Answer :members: .. attribute:: qname - A ``dns.name.Name``, the query name. + A :py:class:`dns.name.Name`, the query name. .. attribute:: rdclass @@ -126,11 +129,11 @@ The dns.resolver.Resolver and dns.resolver.Answer Classes .. attribute:: response - A ``dns.message.QueryMessage``, the response message. + A :py:class:`dns.message.QueryMessage`, the response message. .. attribute:: rrset - A ``dns.rrset.RRset`` or ``None``, the answer RRset. + A :py:class:`dns.rrset.RRset` or ``None``, the answer RRset. .. attribute:: expiration @@ -138,6 +141,6 @@ The dns.resolver.Resolver and dns.resolver.Answer Classes .. attribute:: canonical_name - A ``dns.name.Name``, the canonical name of the query name, + A :py:class:`dns.name.Name`, the canonical name of the query name, i.e. the owner name of the answer RRset after any CNAME and DNAME chaining. diff --git a/doc/resolver-nameserver.rst b/doc/resolver-nameserver.rst index d5374396..a6850d61 100644 --- a/doc/resolver-nameserver.rst +++ b/doc/resolver-nameserver.rst @@ -3,7 +3,7 @@ The dns.nameserver.Nameserver Classes ------------------------------------- -The ``dns.nameserver.Nameserver`` abstract class represents a remote recursive resolver, +The :py:class:`dns.nameserver.Nameserver` abstract class represents a remote recursive resolver, and is used by the stub resolver to answer queries. .. autoclass:: dns.nameserver.Nameserver @@ -12,7 +12,7 @@ and is used by the stub resolver to answer queries. The dns.nameserver.Do53Nameserver Class --------------------------------------- -The ``dns.nameserver.Do53Nameserver`` class is a ``dns.nameserver.Nameserver`` class used +The :py:class:`dns.nameserver.Do53Nameserver` class is a :py:class:`dns.nameserver.Nameserver` class used to make regular UDP/TCP DNS queries, typically over port 53, to a recursive server. .. autoclass:: dns.nameserver.Do53Nameserver @@ -21,7 +21,7 @@ to make regular UDP/TCP DNS queries, typically over port 53, to a recursive serv The dns.nameserver.DoTNameserver Class --------------------------------------- -The ``dns.nameserver.DoTNameserver`` class is a ``dns.nameserver.Nameserver`` class used +The :py:class:`dns.nameserver.DoTNameserver` class is a :py:class:`dns.nameserver.Nameserver` class used to make DNS-over-TLS (DoT) queries to a recursive server. .. autoclass:: dns.nameserver.DoTNameserver @@ -30,7 +30,7 @@ to make DNS-over-TLS (DoT) queries to a recursive server. The dns.nameserver.DoHNameserver Class --------------------------------------- -The ``dns.nameserver.DoHNameserver`` class is a ``dns.nameserver.Nameserver`` class used +The :py:class:`dns.nameserver.DoHNameserver` class is a :py:class:`dns.nameserver.Nameserver` class used to make DNS-over-HTTPS (DoH) queries to a recursive server. .. autoclass:: dns.nameserver.DoHNameserver @@ -39,7 +39,7 @@ to make DNS-over-HTTPS (DoH) queries to a recursive server. The dns.nameserver.DoQNameserver Class --------------------------------------- -The ``dns.nameserver.DoQNameserver`` class is a ``dns.nameserver.Nameserver`` class used +The :py:class:`dns.nameserver.DoQNameserver` class is a :py:class:`dns.nameserver.Nameserver` class used to make DNS-over-QUIC (DoQ) queries to a recursive server. .. autoclass:: dns.nameserver.DoQNameserver diff --git a/doc/threads.rst b/doc/threads.rst index 670fb54f..bc8a29bf 100644 --- a/doc/threads.rst +++ b/doc/threads.rst @@ -23,7 +23,7 @@ The cache implementations for the resolver are also thread-safe, so if a web-crawling application associates an ``LRUCache`` with a Resolver, it will be safe to have many crawler threads doing resolutions. -The ``dns.query`` methods are also thread-safe. One caveat with these +The :py:mod:`dns.query` methods are also thread-safe. One caveat with these functions is that if a socket or other context (e.g. a Requests session or an SSL context) is passed to the function instead of allowing the function to create it, then it is up to the application to diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst index 73bc2b29..3ac56c1b 100644 --- a/doc/whatsnew.rst +++ b/doc/whatsnew.rst @@ -189,10 +189,10 @@ TBD * Python 3.8 or newer is required. -* The stub resolver now uses instances of ``dns.nameserver.Nameserver`` to represent +* The stub resolver now uses instances of :py:class:`dns.nameserver.Nameserver` to represent remote recursive resolvers, and can communicate using DNS over UDP/TCP, HTTPS, TLS, and QUIC. In additional to being able to specify - an IPv4, IPv6, or HTTPS URL as a nameserver, instances of ``dns.nameserver.Nameserver`` + an IPv4, IPv6, or HTTPS URL as a nameserver, instances of :py:class:`dns.nameserver.Nameserver` are now permitted. * The DNS-over-HTTPS bootstrap address no longer causes URL rewriting. @@ -231,7 +231,7 @@ TBD non-zero pad option will be automatically padded appropriately when converted to wire format. -* ``dns.zone.from_text()`` and ``dns.zone.from_file()`` now have an +* :py:func:`dns.zone.from_text` and :py:func:`dns.zone.from_file` now have an ``allow_directives`` parameter to allow finer control over how directives in zonefiles are processed. @@ -241,7 +241,7 @@ TBD is subject to change in future releases. For asynchronous I/O, both asyncio and Trio are supported, but Curio is not. -* DNSSEC signing support has been added to the ``dns.dnssec`` module, along with +* DNSSEC signing support has been added to the :py:mod:`dns.dnssec` module, along with a number of functions to help generate DS, CDS, and CDNSKEY RRsets. Thank you very much Jakob Schlyter! @@ -297,7 +297,7 @@ This release has no new features, but fixes the following issues: * DNS-over-HTTPS is now supported for asynchronous queries and resolutions. -* ``dns.zonefile.read_rrsets()`` has been added, which allows rrsets in zonefile +* :py:func:`dns.zonefile.read_rrsets` has been added, which allows rrsets in zonefile format, or a restrition of it, to be read. This function is useful for applications that want to read DNS data in text format, but do not want to use a Zone. @@ -367,7 +367,7 @@ This release has no new features, but fixes the following issues: * The license is now the ISC license. -* Rdata is now immutable. Use ``dns.rdata.Rdata.replace()`` to make a new +* Rdata is now immutable. Use :py:meth:`dns.rdata.Rdata.replace` to make a new Rdata based on an existing one. * dns.resolver.resolve() has been added, allowing control of whether search @@ -376,14 +376,14 @@ This release has no new features, but fixes the following issues: behavior can be set at in the resolver object with the ``use_search_by_default`` parameter. The default is False. -* DNS-over-TLS is supported with ``dns.query.tls()``. +* DNS-over-TLS is supported with :py:func:`dns.query.tls`. -* DNS-over-HTTPS is supported with ``dns.query.https()``, and the resolver +* DNS-over-HTTPS is supported with :py:func:`dns.query.https`, and the resolver will use DNS-over-HTTPS for a nameserver which is an HTTPS URL. * Basic query and resolver support for the Trio, Curio, and asyncio - asynchronous I/O libraries has been added in ``dns.asyncquery`` and - ``dns.asyncresolver``. This API should be viewed as experimental as + asynchronous I/O libraries has been added in :py:mod:`dns.asyncquery` and + :py:mod:`dns.asyncresolver`. This API should be viewed as experimental as asynchronous I/O support in dnspython is still evolving. * TSIG now defaults to using SHA-256. diff --git a/doc/zone-class.rst b/doc/zone-class.rst index ed8a9fde..5f6003c7 100644 --- a/doc/zone-class.rst +++ b/doc/zone-class.rst @@ -3,36 +3,43 @@ The dns.zone.Zone Class ----------------------- -The ``Zone`` class provides a non-thread-safe implementation of a DNS zone, -as well as a lightweight translation mechanism that allows it to be atomically -updated. For more complicated transactional needs, or for concurrency, please -use the :py:class:`dns.versioned.Zone` class (described below). +The :py:class:`dns.zone.Zone` class provides a non-thread-safe implementation +of a DNS zone, as well as a lightweight translation mechanism that allows it +to be atomically updated. For more complicated transactional needs, or for +concurrency, please use the :py:class:`dns.versioned.Zone` class (described +below). .. autoclass:: dns.zone.Zone :members: .. attribute:: rdclass - The zone's rdata class, an ``int``; the default is class IN. + The zone's rdata class; the default is class IN. + + :type: :py:class:`dns.rdataclass.RdataClass` .. attribute:: origin - The origin of the zone, a ``dns.name.Name``. + The origin of the zone. + + :type: :py:class:`dns.name.Name` .. attribute:: nodes - A dictionary mapping the names of nodes in the zone to the nodes - themselves. + A dictionary mapping the names of nodes in the zone to the nodes + themselves. .. attribute:: relativize - A ``bool``, which is ``True`` if names in the zone should be relativized. + ``True`` if names in the zone should be relativized. -A ``Zone`` has a class attribute ``node_factory`` which is used to -create new nodes and defaults to ``dns.node.Node``. ``Zone`` may be -subclassed if a different node factory is desired. -The node factory is a class or callable that returns a subclass of -``dns.node.Node``. + :type: bool + +A :py:class:`dns.zone.Zone` has a class attribute ``node_factory`` which is +used to create new nodes and defaults to :py:class:`dns.node.Node`. +:py:class:`dns.zone.Zone` may be subclassed if a different node factory is +desired. The node factory is a class or callable that returns a subclass of +:py:class:`dns.node.Node`. .. autoclass:: dns.zone.ZoneStyle :members: @@ -41,21 +48,23 @@ The node factory is a class or callable that returns a subclass of The dns.versioned.Zone Class ---------------------------- -A versioned Zone is a subclass of ``Zone`` that provides a thread-safe -multiversioned transactional API. There can be many concurrent -readers, of possibly different versions, and at most one active -writer. Others cannot see the changes being made by the writer until +A :py:class:`dns.versioned.Zone` is a subclass of :py:class:`dns.zone.Zone` +that provides a thread-safe multiversioned transactional API. There can be +many concurrent readers, of possibly different versions, and at most one +active writer. Others cannot see the changes being made by the writer until it commits. Versions are immutable once committed. The read-only parts of the standard zone API continue to be available, and are equivalent to doing a single-query read-only transaction. Note that unless reading is done through a transaction, version stability is not guaranteed between successive calls. Attempts to use zone API methods -that directly manipulate the zone, e.g. ``replace_rdataset`` will result -in a ``UseTransaction`` exception. +that directly manipulate the zone, e.g. +:py:meth:`dns.zone.Zone.replace_rdataset`, will result in a +:py:exc:`dns.versioned.UseTransaction` exception. -Transactions are context managers, and are created with ``reader()`` or -``writer()``. For example: +Transactions are context managers, and are created with +:py:meth:`dns.versioned.Zone.reader` or +:py:meth:`dns.versioned.Zone.writer`. For example: :: @@ -70,7 +79,10 @@ Transactions are context managers, and are created with ``reader()`` or '10.0.0.1')) txn.set_serial() -See below for more information on the ``Transaction`` API. +See below for more information on the :py:class:`dns.transaction.Transaction` +API. + +.. autoexception:: dns.versioned.UseTransaction .. autoclass:: dns.versioned.Zone :exclude-members: delete_node, delete_rdataset, replace_rdataset @@ -78,20 +90,52 @@ See below for more information on the ``Transaction`` API. .. attribute:: rdclass - The zone's rdata class, an ``int``; the default is class IN. + The zone's rdata class; the default is class IN. + + :type: :py:class:`dns.rdataclass.RdataClass` .. attribute:: origin - The origin of the zone, a ``dns.name.Name``. + The origin of the zone. + + :type: :py:class:`dns.name.Name` .. attribute:: nodes - A dictionary mapping the names of nodes in the zone to the nodes - themselves. + A dictionary mapping the names of nodes in the zone to the nodes + themselves. .. attribute:: relativize - A ``bool``, which is ``True`` if names in the zone should be relativized. + ``True`` if names in the zone should be relativized. + + :type: bool + + +The Version Classes +------------------- + +.. autoclass:: dns.zone.Version + :members: + +.. autoclass:: dns.zone.WritableVersion + :members: + +.. autoclass:: dns.zone.ImmutableVersion + :members: + +.. autoclass:: dns.zone.VersionedNode + :members: + +.. autoclass:: dns.zone.ImmutableVersionedNode + :members: + + +The Zone Transaction Class +-------------------------- + +.. autoclass:: dns.zone.Transaction + :members: The TransactionManager Class @@ -109,3 +153,57 @@ The Transaction Class .. autoclass:: dns.transaction.Transaction :members: +.. autoexception:: dns.transaction.AlreadyEnded + +.. autoexception:: dns.transaction.DeleteNotExact + +.. autoexception:: dns.transaction.ReadOnly + + +The dns.btreezone.Zone Class +---------------------------- + +:py:class:`dns.btreezone.Zone` is a subclass of :py:class:`dns.versioned.Zone` +backed by a :py:class:`dns.btree.BTreeDict`. It maintains names in DNS +canonical (sorted) order, automatically tracks +:py:class:`dns.btreezone.NodeFlags` (``ORIGIN``, ``DELEGATION``, and ``GLUE``) +on every node as rdatasets are added or removed, and shares BTree structure +between versions for efficient copy-on-write behaviour. + +Committed versions expose :py:meth:`~dns.btreezone.ImmutableVersion.bounds`, +which returns the nearest names and closest encloser for any query name. This +information is useful both for constructing authoritative responses and for +generating on-the-fly DNSSEC signatures. + +.. autoclass:: dns.btreezone.Zone + :members: + +The btreezone Node Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: dns.btreezone.NodeFlags + :members: + :inherited-members: + +.. autoclass:: dns.btreezone.Node + :members: + +.. autoclass:: dns.btreezone.ImmutableNode + :members: + +The btreezone Version Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: dns.btreezone.Delegations + :members: + +.. autoclass:: dns.btreezone.WritableVersion + :members: + +.. autoclass:: dns.btreezone.ImmutableVersion + :members: + :inherited-members: + +.. autoclass:: dns.btreezone.Bounds + :members: + diff --git a/doc/zonefile.rst b/doc/zonefile.rst index 50edd164..2b640a35 100644 --- a/doc/zonefile.rst +++ b/doc/zonefile.rst @@ -3,7 +3,7 @@ The RRSet Reader ---------------- -``dns.zonefile.read_rrsets()`` reads one or more RRsets from text format. It +:py:func:`dns.zonefile.read_rrsets` reads one or more RRsets from text format. It is designed to be used in situations where you are processing DNS data in text format, but do not want or need a valid zone. For example, a DNS registry web application might want to allow the user to input RRs. @@ -50,8 +50,8 @@ The ``Reader`` class reads data in DNS zonefile format, or various restrictions of that format, and converts it to a sequence of operations in a transaction. -This class is primarily used by ``dns.zone.Zone.from_text()`` and -``dns.zonefile.read_rrsets``, but may be useful for other software which needs +This class is primarily used by :py:func:`dns.zone.from_text` and +:py:func:`dns.zonefile.read_rrsets`, but may be useful for other software which needs to process the zonefile format. .. autoclass:: dns.zonefile.Reader