diff options
| -rw-r--r-- | dns/renderer.py | 124 | ||||
| -rw-r--r-- | dns/tokenizer.py | 159 | ||||
| -rw-r--r-- | doc/exceptions.rst | 5 |
3 files changed, 110 insertions, 178 deletions
diff --git a/dns/renderer.py b/dns/renderer.py index 670fb28..2025f68 100644 --- a/dns/renderer.py +++ b/dns/renderer.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. +# Copyright (C) 2001-2017 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -32,7 +32,6 @@ ADDITIONAL = 3 class Renderer(object): - """Helper class for building DNS wire-format messages. Most applications can use the higher-level L{dns.message.Message} @@ -54,41 +53,27 @@ class Renderer(object): r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac) wire = r.get_wire() - @ivar output: where rendering is written - @type output: BytesIO object - @ivar id: the message id - @type id: int - @ivar flags: the message flags - @type flags: int - @ivar max_size: the maximum size of the message - @type max_size: int - @ivar origin: the origin to use when rendering relative names - @type origin: dns.name.Name object - @ivar compress: the compression table - @type compress: dict - @ivar section: the section currently being rendered - @type section: int (dns.renderer.QUESTION, dns.renderer.ANSWER, - dns.renderer.AUTHORITY, or dns.renderer.ADDITIONAL) - @ivar counts: list of the number of RRs in each section - @type counts: int list of length 4 - @ivar mac: the MAC of the rendered message (if TSIG was used) - @type mac: string + output, a BytesIO, where rendering is written + + id: the message id + + flags: the message flags + + max_size: the maximum size of the message + + origin: the origin to use when rendering relative names + + compress: the compression table + + section: an int, the section currently being rendered + + counts: list of the number of RRs in each section + + mac: the MAC of the rendered message (if TSIG was used) """ def __init__(self, id=None, flags=0, max_size=65535, origin=None): - """Initialize a new renderer. - - @param id: the message id - @type id: int - @param flags: the DNS message flags - @type flags: int - @param max_size: the maximum message size; the default is 65535. - If rendering results in a message greater than I{max_size}, - then L{dns.exception.TooBig} will be raised. - @type max_size: int - @param origin: the origin to use when rendering relative names - @type origin: dns.name.Name or None. - """ + """Initialize a new renderer.""" self.output = BytesIO() if id is None: @@ -105,12 +90,9 @@ class Renderer(object): self.mac = '' def _rollback(self, where): - """Truncate the output buffer at offset I{where}, and remove any + """Truncate the output buffer at offset *where*, and remove any compression table entries that pointed beyond the truncation point. - - @param where: the offset - @type where: int """ self.output.seek(where) @@ -128,9 +110,7 @@ class Renderer(object): Sections must be rendered order: QUESTION, ANSWER, AUTHORITY, ADDITIONAL. Sections may be empty. - @param section: the section - @type section: int - @raises dns.exception.FormError: an attempt was made to set + Raises dns.exception.FormError if an attempt was made to set a section value less than the current section. """ @@ -140,15 +120,7 @@ class Renderer(object): self.section = section def add_question(self, qname, rdtype, rdclass=dns.rdataclass.IN): - """Add a question to the message. - - @param qname: the question name - @type qname: dns.name.Name - @param rdtype: the question rdata type - @type rdtype: int - @param rdclass: the question rdata class - @type rdclass: int - """ + """Add a question to the message.""" self._set_section(QUESTION) before = self.output.tell() @@ -165,11 +137,6 @@ class Renderer(object): Any keyword arguments are passed on to the rdataset's to_wire() routine. - - @param section: the section - @type section: int - @param rrset: the rrset - @type rrset: dns.rrset.RRset object """ self._set_section(section) @@ -187,13 +154,6 @@ class Renderer(object): Any keyword arguments are passed on to the rdataset's to_wire() routine. - - @param section: the section - @type section: int - @param name: the owner name - @type name: dns.name.Name object - @param rdataset: the rdataset - @type rdataset: dns.rdataset.Rdataset object """ self._set_section(section) @@ -207,19 +167,7 @@ class Renderer(object): self.counts[section] += n def add_edns(self, edns, ednsflags, payload, options=None): - """Add an EDNS OPT record to the message. - - @param edns: The EDNS level to use. - @type edns: int - @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 options: The EDNS options list - @type options: list of dns.edns.Option instances - @see: RFC 2671 - """ + """Add an EDNS OPT record to the message.""" # make sure the EDNS version in ednsflags agrees with edns ednsflags &= long(0xFF00FFFF) @@ -255,26 +203,7 @@ class Renderer(object): def add_tsig(self, keyname, secret, fudge, id, tsig_error, other_data, request_mac, algorithm=dns.tsig.default_algorithm): - """Add a TSIG signature to the message. - - @param keyname: the TSIG key name - @type keyname: dns.name.Name object - @param secret: the secret to use - @type secret: string - @param fudge: TSIG time fudge - @type fudge: int - @param id: the message id to encode in the tsig signature - @type 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 request_mac: This message is a response to the request which - had the specified MAC. - @type request_mac: string - @param algorithm: the TSIG algorithm to use - @type algorithm: dns.name.Name object - """ + """Add a TSIG signature to the message.""" self._set_section(ADDITIONAL) before = self.output.tell() @@ -321,9 +250,6 @@ class Renderer(object): self.output.seek(0, 2) def get_wire(self): - """Return the wire format message. - - @rtype: string - """ + """Return the wire format message.""" return self.output.getvalue() diff --git a/dns/tokenizer.py b/dns/tokenizer.py index 04b9825..3c9bd37 100644 --- a/dns/tokenizer.py +++ b/dns/tokenizer.py @@ -1,4 +1,4 @@ -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. +# Copyright (C) 2003-2017 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose with or without fee is hereby granted, @@ -44,32 +44,20 @@ DELIMITER = 6 class UngetBufferFull(dns.exception.DNSException): - """An attempt was made to unget a token when the unget buffer was full.""" class Token(object): - """A DNS master file format token. - @ivar ttype: The token type - @type ttype: int - @ivar value: The token value - @type value: string - @ivar has_escape: Does the token value contain escapes? - @type has_escape: bool + ttype: The token type + value: The token value + has_escape: Does the token value contain escapes? """ def __init__(self, ttype, value='', has_escape=False): - """Initialize a token instance. - - @param ttype: The token type - @type ttype: int - @param value: The token value - @type value: string - @param has_escape: Does the token value contain escapes? - @type has_escape: bool - """ + """Initialize a token instance.""" + self.ttype = ttype self.value = value self.has_escape = has_escape @@ -160,46 +148,43 @@ class Token(object): class Tokenizer(object): - """A DNS master file format tokenizer. - A token is a (type, value) tuple, where I{type} is an int, and - I{value} is a string. The valid types are EOF, EOL, WHITESPACE, - IDENTIFIER, QUOTED_STRING, COMMENT, and DELIMITER. - - @ivar file: The file to tokenize - @type file: file - @ivar ungotten_char: The most recently ungotten character, or None. - @type ungotten_char: string - @ivar ungotten_token: The most recently ungotten token, or None. - @type ungotten_token: (int, string) token tuple - @ivar multiline: The current multiline level. This value is increased + A token object is basically a (type, value) tuple. The valid + types are EOF, EOL, WHITESPACE, IDENTIFIER, QUOTED_STRING, + COMMENT, and DELIMITER. + + file: The file to tokenize + + ungotten_char: The most recently ungotten character, or None. + + ungotten_token: The most recently ungotten token, or None. + + multiline: The current multiline level. This value is increased by one every time a '(' delimiter is read, and decreased by one every time a ')' delimiter is read. - @type multiline: int - @ivar quoting: This variable is true if the tokenizer is currently + + quoting: This variable is true if the tokenizer is currently reading a quoted string. - @type quoting: bool - @ivar eof: This variable is true if the tokenizer has encountered EOF. - @type eof: bool - @ivar delimiters: The current delimiter dictionary. - @type delimiters: dict - @ivar line_number: The current line number - @type line_number: int - @ivar filename: A filename that will be returned by the L{where} method. - @type filename: string + + eof: This variable is true if the tokenizer has encountered EOF. + + delimiters: The current delimiter dictionary. + + line_number: The current line number + + filename: A filename that will be returned by the where() method. """ def __init__(self, f=sys.stdin, filename=None): """Initialize a tokenizer instance. - @param f: The file to tokenize. The default is sys.stdin. + f: The file to tokenize. The default is sys.stdin. This parameter may also be a string, in which case the tokenizer will take its input from the contents of the string. - @type f: file or string - @param filename: the name of the filename that the L{where} method + + filename: the name of the filename that the where() method will return. - @type filename: string """ if isinstance(f, text_type): @@ -228,7 +213,6 @@ class Tokenizer(object): def _get_char(self): """Read a character from input. - @rtype: string """ if self.ungotten_char is None: @@ -248,7 +232,7 @@ class Tokenizer(object): def where(self): """Return the current location in the input. - @rtype: (string, int) tuple. The first item is the filename of + Returns a (string, int) tuple. The first item is the filename of the input, the second is the current line number. """ @@ -261,9 +245,8 @@ class Tokenizer(object): an error to try to unget a character when the unget buffer is not empty. - @param c: the character to unget - @type c: string - @raises UngetBufferFull: there is already an ungotten char + c: the character to unget + raises UngetBufferFull: there is already an ungotten char """ if self.ungotten_char is not None: @@ -278,7 +261,7 @@ class Tokenizer(object): If the tokenizer is in multiline mode, then newlines are whitespace. - @rtype: int + Returns the number of characters skipped. """ skipped = 0 @@ -293,15 +276,17 @@ class Tokenizer(object): def get(self, want_leading=False, want_comment=False): """Get the next token. - @param want_leading: If True, return a WHITESPACE token if the + want_leading: If True, return a WHITESPACE token if the first character read is whitespace. The default is False. - @type want_leading: bool - @param want_comment: If True, return a COMMENT token if the + + want_comment: If True, return a COMMENT token if the first token read is a comment. The default is False. - @type want_comment: bool - @rtype: Token object - @raises dns.exception.UnexpectedEnd: input ended prematurely - @raises dns.exception.SyntaxError: input was badly formed + + Raises dns.exception.UnexpectedEnd: input ended prematurely + + Raises dns.exception.SyntaxError: input was badly formed + + Returns a Token. """ if self.ungotten_token is not None: @@ -420,9 +405,9 @@ class Tokenizer(object): an error to try to unget a token when the unget buffer is not empty. - @param token: the token to unget - @type token: Token object - @raises UngetBufferFull: there is already an ungotten token + token: the token to unget + + Raises UngetBufferFull: there is already an ungotten token """ if self.ungotten_token is not None: @@ -431,7 +416,8 @@ class Tokenizer(object): def next(self): """Return the next item in an iteration. - @rtype: (int, string) + + Returns a Token. """ token = self.get() @@ -449,8 +435,9 @@ class Tokenizer(object): def get_int(self): """Read the next token and interpret it as an integer. - @raises dns.exception.SyntaxError: - @rtype: int + Raises dns.exception.SyntaxError if not an integer. + + Returns an int. """ token = self.get().unescape() @@ -464,8 +451,9 @@ class Tokenizer(object): """Read the next token and interpret it as an 8-bit unsigned integer. - @raises dns.exception.SyntaxError: - @rtype: int + Raises dns.exception.SyntaxError if not an 8-bit unsigned integer. + + Returns an int. """ value = self.get_int() @@ -478,8 +466,9 @@ class Tokenizer(object): """Read the next token and interpret it as a 16-bit unsigned integer. - @raises dns.exception.SyntaxError: - @rtype: int + Raises dns.exception.SyntaxError if not a 16-bit unsigned integer. + + Returns an int. """ value = self.get_int() @@ -492,8 +481,9 @@ class Tokenizer(object): """Read the next token and interpret it as a 32-bit unsigned integer. - @raises dns.exception.SyntaxError: - @rtype: int + Raises dns.exception.SyntaxError if not a 32-bit unsigned integer. + + Returns an int. """ token = self.get().unescape() @@ -510,8 +500,9 @@ class Tokenizer(object): def get_string(self, origin=None): """Read the next token and interpret it as a string. - @raises dns.exception.SyntaxError: - @rtype: string + Raises dns.exception.SyntaxError if not a string. + + Returns a string. """ token = self.get().unescape() @@ -520,10 +511,11 @@ class Tokenizer(object): return token.value def get_identifier(self, origin=None): - """Read the next token and raise an exception if it is not an identifier. + """Read the next token, which should be an identifier. + + Raises dns.exception.SyntaxError if not an identifier. - @raises dns.exception.SyntaxError: - @rtype: string + Returns a string. """ token = self.get().unescape() @@ -534,8 +526,10 @@ class Tokenizer(object): def get_name(self, origin=None): """Read the next token and interpret it as a DNS name. - @raises dns.exception.SyntaxError: - @rtype: dns.name.Name object""" + Raises dns.exception.SyntaxError if not a name. + + Returns a dns.name.Name. + """ token = self.get() if not token.is_identifier(): @@ -546,8 +540,7 @@ class Tokenizer(object): """Read the next token and raise an exception if it isn't EOL or EOF. - @raises dns.exception.SyntaxError: - @rtype: string + Returns a string. """ token = self.get() @@ -558,6 +551,14 @@ class Tokenizer(object): return token.value def get_ttl(self): + """Read the next token and interpret it as a DNS TTL. + + Raises dns.exception.SyntaxError or dns.ttl.BadTTL if not an + identifier or badly formed. + + Returns an int. + """ + token = self.get().unescape() if not token.is_identifier(): raise dns.exception.SyntaxError('expecting an identifier') diff --git a/doc/exceptions.rst b/doc/exceptions.rst index cc04afc..57d1d5f 100644 --- a/doc/exceptions.rst +++ b/doc/exceptions.rst @@ -64,6 +64,11 @@ dns.rdataset Exceptions .. autoexception:: dns.rdataset.DifferingCovers .. autoexception:: dns.rdataset.IncompatibleTypes +dns.tokenizer Exceptions +------------------------ + +.. autoexception:: dns.tokenizer.UngetBufferFull + dns.ttl Exceptions ------------------ |
