]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Message doco.
authorBob Halley <halley@dnspython.org>
Sat, 14 Jan 2017 18:22:45 +0000 (10:22 -0800)
committerBob Halley <halley@dnspython.org>
Sat, 14 Jan 2017 18:22:45 +0000 (10:22 -0800)
Add constants to allow a section name to be specified symbolically rather
than by passing the actual section list value.

dns/message.py
doc/message-class.rst
tests/test_message.py

index acb89f832b8c5fea222258f52f6662389d6322ea..b403d70f84d25f35f1e69b76f1d533077ed56ffa 100644 (file)
@@ -66,10 +66,20 @@ class UnknownTSIGKey(dns.exception.DNSException):
     """A TSIG with an unknown key was received."""
 
 
-class Message(object):
-    """A DNS message.
+#: The question section number
+QUESTION = 0
 
-    """
+#: The answer section number
+ANSWER = 1
+
+#: The authority section number
+AUTHORITY = 2
+
+#: The additional section number
+ADDITIONAL = 3
+
+class Message(object):
+    """A DNS message."""
 
     def __init__(self, id=None):
         if id is None:
@@ -112,10 +122,10 @@ class Message(object):
     def to_text(self, origin=None, relativize=True, **kw):
         """Convert the message to text.
 
-        The I{origin}, I{relativize}, and any other keyword
-        arguments are passed to the rrset to_wire() method.
+        The *origin*, *relativize*, and any other keyword
+        arguments are passed to the RRset ``to_wire()`` method.
 
-        @rtype: string
+        Returns a ``text``.
         """
 
         s = StringIO()
@@ -169,7 +179,10 @@ class Message(object):
     def __eq__(self, other):
         """Two messages are equal if they have the same content in the
         header, question, answer, and authority sections.
-        @rtype: bool"""
+
+        Returns a ``bool``.
+        """
+
         if not isinstance(other, Message):
             return False
         if self.id != other.id:
@@ -197,13 +210,14 @@ class Message(object):
         return True
 
     def __ne__(self, other):
-        """Are two messages not equal?
-        @rtype: bool"""
         return not self.__eq__(other)
 
     def is_response(self, other):
-        """Is other a response to self?
-        @rtype: bool"""
+        """Is this message a response to *other*?
+
+        Returns a ``bool``.
+        """
+
         if other.flags & dns.flags.QR == 0 or \
            self.id != other.id or \
            dns.opcode.from_flags(self.flags) != \
@@ -223,14 +237,48 @@ class Message(object):
         return True
 
     def section_number(self, section):
+        """Return the "section number" of the specified section for use
+        in indexing.  The question section is 0, the answer section is 1,
+        the authority section is 2, and the additional section is 3.
+
+        *section* is one of the section attributes of this message.
+
+        Raises ``ValueError`` if the section isn't known.
+
+        Returns an ``int``.
+        """
+
         if section is self.question:
-            return 0
+            return QUESTION
         elif section is self.answer:
-            return 1
+            return ANSWER
         elif section is self.authority:
-            return 2
+            return AUTHORITY
         elif section is self.additional:
-            return 3
+            return ADDITIONAL
+        else:
+            raise ValueError('unknown section')
+
+    def section_from_number(self, number):
+        """Return the "section number" of the specified section for use
+        in indexing.  The question section is 0, the answer section is 1,
+        the authority section is 2, and the additional section is 3.
+
+        *section* is one of the section attributes of this message.
+
+        Raises ``ValueError`` if the section isn't known.
+
+        Returns an ``int``.
+        """
+
+        if number == QUESTION:
+            return self.question
+        elif number == ANSWER:
+            return self.answer
+        elif number == AUTHORITY:
+            return self.authority
+        elif number == ADDITIONAL:
+            return self.additional
         else:
             raise ValueError('unknown section')
 
@@ -239,30 +287,45 @@ class Message(object):
                    force_unique=False):
         """Find the RRset with the given attributes in the specified section.
 
-        @param section: the section of the message to look in, e.g.
-        self.answer.
-        @type section: list of dns.rrset.RRset objects
-        @param name: the name of the RRset
-        @type name: dns.name.Name object
-        @param rdclass: the class of the RRset
-        @type rdclass: int
-        @param rdtype: the type of the RRset
-        @type rdtype: int
-        @param covers: the covers value of the RRset
-        @type covers: int
-        @param deleting: the deleting value of the RRset
-        @type deleting: int
-        @param create: If True, create the RRset if it is not found.
-        The created RRset is appended to I{section}.
-        @type create: bool
-        @param force_unique: If True and create is also True, create a
-        new RRset regardless of whether a matching RRset exists already.
-        @type force_unique: bool
-        @raises KeyError: the RRset was not found and create was False
-        @rtype: dns.rrset.RRset object"""
-
-        key = (self.section_number(section),
-               name, rdclass, rdtype, covers, deleting)
+        *section*, an ``int`` section number, or one of the section
+        attributes of this message.  This specifies the
+        the section of the message to search.  For example::
+
+            my_message.find_rrset(my_message.answer, name, rdclass, rdtype)
+            my_message.find_rrset(dns.message.ANSWER, name, rdclass, rdtype)
+
+        *name*, a ``dns.name.Name``, the name of the RRset.
+
+        *rdclass*, an ``int``, the class of the RRset.
+
+        *rdtype*, an ``int``, the type of the RRset.
+
+        *covers*, an ``int`` or ``None``, the covers value of the RRset.
+        The default is ``None``.
+
+        *deleting*, an ``int`` 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.
+
+        Raises ``KeyError`` if the RRset was not found and create was
+        ``False``.
+
+        Returns a ``dns.rrset.RRset object``.
+        """
+
+        if isinstance(section, int):
+            section_number = section
+            section = self.section_from_number(section_number)
+        else:
+            section_number = self.section_number(section)
+        key = (section_number, name, rdclass, rdtype, covers, deleting)
         if not force_unique:
             if self.index is not None:
                 rrset = self.index.get(key)
@@ -287,26 +350,35 @@ class Message(object):
 
         If the RRset is not found, None is returned.
 
-        @param section: the section of the message to look in, e.g.
-        self.answer.
-        @type section: list of dns.rrset.RRset objects
-        @param name: the name of the RRset
-        @type name: dns.name.Name object
-        @param rdclass: the class of the RRset
-        @type rdclass: int
-        @param rdtype: the type of the RRset
-        @type rdtype: int
-        @param covers: the covers value of the RRset
-        @type covers: int
-        @param deleting: the deleting value of the RRset
-        @type deleting: int
-        @param create: If True, create the RRset if it is not found.
-        The created RRset is appended to I{section}.
-        @type create: bool
-        @param force_unique: If True and create is also True, create a
-        new RRset regardless of whether a matching RRset exists already.
-        @type force_unique: bool
-        @rtype: dns.rrset.RRset object or None"""
+        *section*, an ``int`` section number, 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)
+
+        *name*, a ``dns.name.Name``, the name of the RRset.
+
+        *rdclass*, an ``int``, the class of the RRset.
+
+        *rdtype*, an ``int``, the type of the RRset.
+
+        *covers*, an ``int`` or ``None``, the covers value of the RRset.
+        The default is ``None``.
+
+        *deleting*, an ``int`` 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.
+
+        Returns a ``dns.rrset.RRset object`` or ``None``.
+        """
 
         try:
             rrset = self.find_rrset(section, name, rdclass, rdtype, covers,
@@ -319,17 +391,19 @@ class Message(object):
         """Return a string containing the message in DNS compressed wire
         format.
 
-        Additional keyword arguments are passed to the rrset to_wire()
+        Additional keyword arguments are passed to the RRset ``to_wire()``
         method.
 
-        @param origin: The origin to be appended to any relative names.
-        @type origin: dns.name.Name object
-        @param max_size: The maximum size of the wire format output; default
-        is 0, which means 'the message's request payload, if nonzero, or
-        65536'.
-        @type max_size: int
-        @raises dns.exception.TooBig: max_size was exceeded
-        @rtype: string
+        *origin*, a ``dns.name.Name`` or ``None``, the origin to be appended
+        to any relative names.
+
+        *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".
+
+        Raises ``dns.exception.TooBig`` if *max_size* was exceeded.
+
+        Returns a ``binary``.
         """
 
         if max_size == 0:
@@ -362,30 +436,34 @@ class Message(object):
         return r.get_wire()
 
     def use_tsig(self, keyring, keyname=None, fudge=300,
-                 original_id=None, tsig_error=0, other_data='',
+                 original_id=None, tsig_error=0, other_data=b'',
                  algorithm=dns.tsig.default_algorithm):
         """When sending, a TSIG signature using the specified keyring
         and keyname should be added.
 
-        @param keyring: The TSIG keyring to use; defaults to None.
-        @type keyring: dict
-        @param keyname: The name of the TSIG key to use; defaults to None.
-        The key must be defined in the keyring.  If a keyring is specified
-        but a keyname is not, then 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 keyring is used, unless
-        they know the keyring contains only one key.
-        @type keyname: dns.name.Name or string
-        @param fudge: TSIG time fudge; default is 300 seconds.
-        @type fudge: int
-        @param original_id: TSIG original id; defaults to the message's id
-        @type original_id: int
-        @param tsig_error: TSIG error code; default is 0.
-        @type tsig_error: int
-        @param other_data: TSIG other data.
-        @type other_data: string
-        @param algorithm: The TSIG algorithm to use; defaults to
-        dns.tsig.default_algorithm
+        See the documentation of the Message class for a complete
+        description of the keyring dictionary.
+
+        *keyring*, a ``dict``, the TSIG keyring to use.  If a
+        *keyring* is specified but a *keyname* is not, then 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 keyring is used, unless they
+        know the keyring contains only one key.
+
+        *keyname*, a ``dns.name.Name`` or ``None``, the name of the TSIG key
+        to use; defaults to ``None``. The key must be defined in the keyring.
+
+        *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 ``binary``, the TSIG other data.
+
+        *algorithm*, a ``dns.name.Name``, the TSIG algorithm to use.
         """
 
         self.keyring = keyring
@@ -407,23 +485,26 @@ class Message(object):
     def use_edns(self, edns=0, ednsflags=0, payload=1280, request_payload=None,
                  options=None):
         """Configure EDNS behavior.
-        @param edns: 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'.
-        @type edns: int or bool or None
-        @param ednsflags: EDNS flag values.
-        @type ednsflags: int
-        @param payload: The EDNS sender's payload field, which is the maximum
-        size of UDP datagram the sender can handle.
-        @type payload: int
-        @param request_payload: The EDNS payload size to use when sending
-        this message.  If not specified, defaults to the value of payload.
-        @type request_payload: int or None
-        @param options: The EDNS options
-        @type options: None or list of dns.edns.Option objects
-        @see: RFC 2671
-        """
+
+        *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.
+o        """
+
         if edns is None or edns is False:
             edns = -1
         if edns is True:
@@ -449,11 +530,13 @@ class Message(object):
 
     def want_dnssec(self, wanted=True):
         """Enable or disable 'DNSSEC desired' flag in requests.
-        @param wanted: Is DNSSEC desired?  If True, EDNS is enabled if
-        required, and then the DO bit is set.  If False, the DO bit is
-        cleared if EDNS is enabled.
-        @type wanted: bool
+
+        *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.
         """
+
         if wanted:
             if self.edns < 0:
                 self.use_edns()
@@ -463,14 +546,15 @@ class Message(object):
 
     def rcode(self):
         """Return the rcode.
-        @rtype: int
+
+        Returns an ``int``.
         """
         return dns.rcode.from_flags(self.flags, self.ednsflags)
 
     def set_rcode(self, rcode):
         """Set the rcode.
-        @param rcode: the rcode
-        @type rcode: int
+
+        *rcode*, an ``int``, is the rcode to set.
         """
         (value, evalue) = dns.rcode.to_flags(rcode)
         self.flags &= 0xFFF0
@@ -482,14 +566,15 @@ class Message(object):
 
     def opcode(self):
         """Return the opcode.
-        @rtype: int
+
+        Returns an ``int``.
         """
         return dns.opcode.from_flags(self.flags)
 
     def set_opcode(self, opcode):
         """Set the opcode.
-        @param opcode: the opcode
-        @type opcode: int
+
+        *opcode*, an ``int``, is the opcode to set.
         """
         self.flags &= 0x87FF
         self.flags |= dns.opcode.to_flags(opcode)
@@ -499,23 +584,16 @@ class _WireReader(object):
 
     """Wire format reader.
 
-    @ivar wire: the wire-format message.
-    @type wire: string
-    @ivar message: The message object being built
-    @type message: dns.message.Message object
-    @ivar current: When building a message object from wire format, this
+    wire: a binary, is the wire-format message.
+    message: The message object being built
+    current: When building a message object from wire format, this
     variable contains the offset from the beginning of wire of the next octet
     to be read.
-    @type current: int
-    @ivar updating: Is the message a dynamic update?
-    @type updating: bool
-    @ivar one_rr_per_rrset: Put each RR into its own RRset?
-    @type one_rr_per_rrset: bool
-    @ivar ignore_trailing: Ignore trailing junk at end of request?
-    @type ignore_trailing: bool
-    @ivar zone_rdclass: The class of the zone in messages which are
+    updating: Is the message a dynamic update?
+    one_rr_per_rrset: Put each RR into its own RRset?
+    ignore_trailing: Ignore trailing junk at end of request?
+    zone_rdclass: The class of the zone in messages which are
     DNS dynamic updates.
-    @type zone_rdclass: int
     """
 
     def __init__(self, wire, message, question_only=False,
@@ -530,10 +608,9 @@ class _WireReader(object):
         self.ignore_trailing = ignore_trailing
 
     def _get_question(self, qcount):
-        """Read the next I{qcount} records from the wire data and add them to
+        """Read the next *qcount* records from the wire data and add them to
         the question section.
-        @param qcount: the number of questions in the message
-        @type qcount: int"""
+        """
 
         if self.updating and qcount > 1:
             raise dns.exception.FormError
@@ -556,10 +633,10 @@ class _WireReader(object):
     def _get_section(self, section, count):
         """Read the next I{count} records from the wire data and add them to
         the specified section.
-        @param section: the section of the message to which to add records
-        @type section: list of dns.rrset.RRset objects
-        @param count: the number of records to read
-        @type count: int"""
+
+        section: the section of the message to which to add records
+        count: the number of records to read
+        """
 
         if self.updating or self.one_rr_per_rrset:
             force_unique = True
@@ -684,38 +761,51 @@ def from_wire(wire, keyring=None, request_mac='', xfr=False, origin=None,
     """Convert a DNS wire format message into a message
     object.
 
-    @param keyring: The keyring to use if the message is signed.
-    @type keyring: dict
-    @param request_mac: If the message is a response to a TSIG-signed request,
-    I{request_mac} should be set to the MAC of that request.
-    @type request_mac: string
-    @param xfr: Is this message part of a zone transfer?
-    @type xfr: bool
-    @param origin: If the message is part of a zone transfer, I{origin}
-    should be the origin name of the zone.
-    @type origin: dns.name.Name object
-    @param tsig_ctx: The ongoing TSIG context, used when validating zone
-    transfers.
-    @type tsig_ctx: hmac.HMAC object
-    @param multi: Is this message part of a multiple message sequence?
-    @type multi: bool
-    @param first: Is this message standalone, or the first of a multi
-    message sequence?
-    @type first: bool
-    @param question_only: Read only up to the end of the question section?
-    @type question_only: bool
-    @param one_rr_per_rrset: Put each RR into its own RRset
-    @type one_rr_per_rrset: bool
-    @param ignore_trailing: Ignore trailing junk at end of request?
-    @type ignore_trailing: bool
-    @raises ShortHeader: The message is less than 12 octets long.
-    @raises TrailingJunk: There were octets in the message past the end
-    of the proper DNS message.
-    @raises BadEDNS: An OPT record was in the wrong section, or occurred more
-    than once.
-    @raises BadTSIG: A TSIG record was not the last record of the additional
-    data section.
-    @rtype: dns.message.Message object"""
+    *keyring*, a ``dict``, the keyring to use if the message is signed.
+
+    *request_mac*, a ``binary``.  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.
+
+    *tsig_ctx*, a ``hmac.HMAC`` objext, the ongoing TSIG context, used
+    when validating zone transfers.
+
+    *multi*, a ``bool``, should be set to ``True`` if this message
+    part of a multiple message sequence.
+
+    *first*, a ``bool``, should be set to ``True`` if this message is
+    stand-alone, or the first message in a multi-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.
+
+    Raises ``dns.message.ShortHeader`` if the message is less than 12 octets
+    long.
+
+    Raises ``dns.messaage.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.
+
+    Returns a ``dns.message.Message``.
+    """
 
     m = Message(id=0)
     m.keyring = keyring
@@ -737,18 +827,12 @@ class _TextReader(object):
 
     """Text format reader.
 
-    @ivar tok: the tokenizer
-    @type tok: dns.tokenizer.Tokenizer object
-    @ivar message: The message object being built
-    @type message: dns.message.Message object
-    @ivar updating: Is the message a dynamic update?
-    @type updating: bool
-    @ivar zone_rdclass: The class of the zone in messages which are
+    tok: the tokenizer.
+    message: The message object being built.
+    updating: Is the message a dynamic update?
+    zone_rdclass: The class of the zone in messages which are
     DNS dynamic updates.
-    @type zone_rdclass: int
-    @ivar last_name: The most recently read name when building a message object
-    from text format.
-    @type last_name: dns.name.Name object
+    last_name: The most recently read name when building a message object.
     """
 
     def __init__(self, text, message):
@@ -921,11 +1005,14 @@ class _TextReader(object):
 def from_text(text):
     """Convert the text format message into a message object.
 
-    @param text: The text format message.
-    @type text: string
-    @raises UnknownHeaderField:
-    @raises dns.exception.SyntaxError:
-    @rtype: dns.message.Message object"""
+    *text*, a ``text``, the text format message.
+
+    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``
+    """
 
     # 'text' can also be a file, but we don't publish that fact
     # since it's an implementation detail.  The official file
@@ -942,11 +1029,15 @@ def from_text(text):
 def from_file(f):
     """Read the next text format message from the specified file.
 
-    @param f: file or string.  If I{f} is a string, it is treated
-    as the name of a file to open.
-    @raises UnknownHeaderField:
-    @raises dns.exception.SyntaxError:
-    @rtype: dns.message.Message object"""
+    *f*, a ``file`` or ``text``.  If *f* is text, it is treated as the
+    pathname of a file to open.
+
+    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``
+    """
 
     str_type = string_types
     opts = 'rU'
@@ -976,30 +1067,35 @@ def make_query(qname, rdtype, rdclass=dns.rdataclass.IN, use_edns=None,
     The query will have a randomly chosen query id, and its DNS flags
     will be set to dns.flags.RD.
 
-    @param qname: The query name.
-    @type qname: dns.name.Name object or string
-    @param rdtype: The desired rdata type.
-    @type rdtype: int
-    @param rdclass: The desired rdata class; the default is class IN.
-    @type rdclass: int
-    @param use_edns: The EDNS level to use; the default is None (no EDNS).
+    qname, a ``dns.name.Name`` or ``text``, the query name.
+
+    *rdtype*, an ``int`` or ``text``, the desired rdata type.
+
+    *rdclass*, an ``int`` or ``text`,  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 (no EDNS).
     See the description of dns.message.Message.use_edns() for the possible
     values for use_edns and their meanings.
-    @type use_edns: int or bool or None
-    @param want_dnssec: Should the query indicate that DNSSEC is desired?
-    @type want_dnssec: bool
-    @param ednsflags: EDNS flag values.
-    @type ednsflags: int
-    @param payload: The EDNS sender's payload field, which is the maximum
-    size of UDP datagram the sender can handle.
-    @type payload: int
-    @param request_payload: The EDNS payload size to use when sending
-    this message.  If not specified, defaults to the value of payload.
-    @type request_payload: int or None
-    @param options: The EDNS options
-    @type options: None or list of dns.edns.Option objects
-    @see: RFC 2671
-    @rtype: dns.message.Message object"""
+
+    *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.
+
+    Returns a ``dns.message.Message``
+    """
 
     if isinstance(qname, string_types):
         qname = dns.name.from_text(qname)
@@ -1048,16 +1144,17 @@ def make_response(query, recursion_available=False, our_payload=8192,
     question section, so the query's question RRsets should not be
     changed.
 
-    @param query: the query to respond to
-    @type query: dns.message.Message object
-    @param recursion_available: should RA be set in the response?
-    @type recursion_available: bool
-    @param our_payload: payload size to advertise in EDNS responses; default
-    is 8192.
-    @type our_payload: int
-    @param fudge: TSIG time fudge; default is 300 seconds.
-    @type fudge: int
-    @rtype: dns.message.Message object"""
+    *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.
+
+    Returns a ``dns.message.Message`` object.
+    """
 
     if query.flags & dns.flags.QR:
         raise dns.exception.FormError('specified query message is not a query')
index 6f6a98e03bc125b5193a6a386bd57f34c81da4aa..13e740e5f15fbb768b0df58235fafbdecbaac02c 100644 (file)
@@ -66,7 +66,7 @@ The dns.message.Message Class
 
    .. attribute:: keyalgorithm
 
-      A ``text``, the TSIG algorithm to use.  Defaults to
+      A ``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.
 
@@ -137,3 +137,11 @@ The dns.message.Message Class
       ``(section, name, rdclass, rdtype, covers, deleting)``.  The default
       is ``{}``.  Indexing improves the performance of finding RRsets.
       Indexing can be disabled by setting the index to ``None``.
+
+The following constants may be used to specify sections in the
+``find_rrset()`` and ``get_rrset()`` methods:
+
+.. autodata:: dns.message.QUESTION
+.. autodata:: dns.message.ANSWER
+.. autodata:: dns.message.AUTHORITY
+.. autodata:: dns.message.ADDITIONAL
index 2ae6800d2be7ced8019cf054f890ed02c7985e97..fc4ad375faabaeaae5cb5df732e113d31f0ed503 100644 (file)
@@ -22,6 +22,9 @@ import binascii
 import dns.exception
 import dns.flags
 import dns.message
+import dns.name
+import dns.rdataclass
+import dns.rdatatype
 from dns._compat import xrange
 
 query_text = """id 1234
@@ -199,5 +202,13 @@ class MessageTestCase(unittest.TestCase):
         m = dns.message.make_query('foo', 'A', options=[])
         self.failUnless(m.edns == 0)
 
+    def test_FindRRset(self):
+        a = dns.message.from_text(answer_text)
+        n = dns.name.from_text('dnspython.org.')
+        rrs1 = a.find_rrset(a.answer, n, dns.rdataclass.IN, dns.rdatatype.SOA)
+        rrs2 = a.find_rrset(dns.message.ANSWER, n, dns.rdataclass.IN,
+                            dns.rdatatype.SOA)
+        self.failUnless(rrs1 == rrs2)
+
 if __name__ == '__main__':
     unittest.main()