diff -Nru dnspython-1.14.0/ChangeLog dnspython-1.15.0/ChangeLog --- dnspython-1.14.0/ChangeLog 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/ChangeLog 2016-09-30 14:41:52.000000000 +0000 @@ -1,3 +1,26 @@ +2016-09-29 Bob Halley + + * IDNA 2008 support is now available if the "idna" module has been + installed and IDNA 2008 is requested. The default IDNA behavior + is still IDNA 2003. The new IDNA codec mechanism is currently + only useful for direct calls to dns.name.from_text() or + dns.name.from_unicode(), but in future releases it will be + deployed throughout dnspython, e.g. so that you can read a + masterfile with an IDNA 2008 codec in force. + + * By default, dns.name.to_unicode() is not strict about which + version of IDNA the input complies with. Strictness can be + requested by using one of the strict IDNA codecs. + + * Add AVC RR support. + + * Some problems with newlines in various output modes have been + addressed. + + * dns.name.to_text() now returns text and not bytes on Python 3.x + + * More miscellaneous fixes for the Python 2/3 codeline merge. + 2016-05-27 Bob Halley * (Version 1.14.0 released) diff -Nru dnspython-1.14.0/debian/changelog dnspython-1.15.0/debian/changelog --- dnspython-1.14.0/debian/changelog 2016-07-15 12:32:11.000000000 +0000 +++ dnspython-1.15.0/debian/changelog 2016-11-02 05:30:45.000000000 +0000 @@ -1,8 +1,19 @@ -dnspython (1.14.0-3~cloud0) xenial-newton; urgency=medium +dnspython (1.15.0-1~cloud0) xenial-ocata; urgency=medium - * New update for the Ubuntu Cloud Archive. + * New upstream release for the Ubuntu Cloud Archive. - -- Openstack Ubuntu Testing Bot Fri, 15 Jul 2016 12:32:11 +0000 + -- Openstack Ubuntu Testing Bot Wed, 02 Nov 2016 05:30:45 +0000 + +dnspython (1.15.0-1) unstable; urgency=medium + + * New upstream release + * Fix file write location in testToFileFilename. + - Add debian/patches/0001-Fix-file-write-location-in-testToFileFilename + .patch + * Bump compat/debhelper version to 9 due to compat levels < 9 being + deprecated + + -- Scott Kitterman Mon, 24 Oct 2016 08:00:17 -0400 dnspython (1.14.0-3) unstable; urgency=medium diff -Nru dnspython-1.14.0/debian/compat dnspython-1.15.0/debian/compat --- dnspython-1.14.0/debian/compat 2016-05-28 16:55:20.000000000 +0000 +++ dnspython-1.15.0/debian/compat 2016-10-24 11:59:15.000000000 +0000 @@ -1 +1 @@ -8 +9 diff -Nru dnspython-1.14.0/debian/control dnspython-1.15.0/debian/control --- dnspython-1.14.0/debian/control 2016-06-13 16:58:55.000000000 +0000 +++ dnspython-1.15.0/debian/control 2016-10-24 11:59:30.000000000 +0000 @@ -3,7 +3,7 @@ Priority: optional Maintainer: Debian Python Modules Team Uploaders: Robert S. Edmonds , Scott Kitterman , Matthew Grant -Build-Depends: debhelper (>= 8.1~), python-all (>= 2.6.6-3~), python-setuptools, python3-all (>= 3.3), python3-setuptools, dh-python, netbase +Build-Depends: debhelper (>= 9~), python-all (>= 2.6.6-3~), python-setuptools, python3-all (>= 3.3), python3-setuptools, dh-python, netbase X-Python3-Version: >= 3.3 Homepage: http://www.dnspython.org Standards-Version: 3.9.8 diff -Nru dnspython-1.14.0/debian/.git-dpm dnspython-1.15.0/debian/.git-dpm --- dnspython-1.14.0/debian/.git-dpm 2016-05-28 16:55:21.000000000 +0000 +++ dnspython-1.15.0/debian/.git-dpm 2016-10-24 11:53:17.000000000 +0000 @@ -1,11 +1,11 @@ # see git-dpm(1) from git-dpm package -742878da7ea7dc02bd127f9254aeb13d7d32a431 -742878da7ea7dc02bd127f9254aeb13d7d32a431 -e97a7fb113a94b0eeb393b630334ffa5de3c8cdd -e97a7fb113a94b0eeb393b630334ffa5de3c8cdd -dnspython_1.14.0.orig.tar.gz -e58c4dcfba3391620038fa303268a34f4ac47832 -144591 +0d1947c117c43af0498ff5563d7acfed903e9bfa +0d1947c117c43af0498ff5563d7acfed903e9bfa +131bfc40a93a1cd64c3a1bccbe3391608733a8dd +131bfc40a93a1cd64c3a1bccbe3391608733a8dd +dnspython_1.15.0.orig.tar.gz +fcb8edb4b307f68a27cd356e7b44f53512b63b5e +144073 debianTag="debian/%e%v" patchedTag="patched/%e%v" upstreamTag="upstream/%e%u" diff -Nru dnspython-1.14.0/debian/patches/0001-Fix-file-write-location-in-testToFileFilename.patch dnspython-1.15.0/debian/patches/0001-Fix-file-write-location-in-testToFileFilename.patch --- dnspython-1.14.0/debian/patches/0001-Fix-file-write-location-in-testToFileFilename.patch 1970-01-01 00:00:00.000000000 +0000 +++ dnspython-1.15.0/debian/patches/0001-Fix-file-write-location-in-testToFileFilename.patch 2016-10-24 11:53:17.000000000 +0000 @@ -0,0 +1,22 @@ +From 0d1947c117c43af0498ff5563d7acfed903e9bfa Mon Sep 17 00:00:00 2001 +From: Scott Kitterman +Date: Mon, 24 Oct 2016 07:52:24 -0400 +Subject: Fix file write location in testToFileFilename. + +--- + tests/test_zone.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/test_zone.py b/tests/test_zone.py +index dbc67c7..3c497a6 100644 +--- a/tests/test_zone.py ++++ b/tests/test_zone.py +@@ -177,7 +177,7 @@ class ZoneTestCase(unittest.TestCase): + def testToFileFilename(self): + z = dns.zone.from_file(here('example'), 'example') + try: +- z.to_file('example3-filename.out') ++ z.to_file(here('example3-filename.out')) + ok = filecmp.cmp(here('example3-filename.out'), + here('example3.good')) + finally: diff -Nru dnspython-1.14.0/debian/patches/0001-Only-run-tests-in-tests-test_resolver.py-that-requir.patch dnspython-1.15.0/debian/patches/0001-Only-run-tests-in-tests-test_resolver.py-that-requir.patch --- dnspython-1.14.0/debian/patches/0001-Only-run-tests-in-tests-test_resolver.py-that-requir.patch 2016-05-28 16:55:21.000000000 +0000 +++ dnspython-1.15.0/debian/patches/0001-Only-run-tests-in-tests-test_resolver.py-that-requir.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -From 742878da7ea7dc02bd127f9254aeb13d7d32a431 Mon Sep 17 00:00:00 2001 -From: Scott Kitterman -Date: Sat, 28 May 2016 02:56:55 -0400 -Subject: Only run tests in tests/test_resolver.py that require an Internet - connection when it is available - ---- - tests/test_resolver.py | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/tests/test_resolver.py b/tests/test_resolver.py -index 29c3959..eb4f23e 100644 ---- a/tests/test_resolver.py -+++ b/tests/test_resolver.py -@@ -16,6 +16,7 @@ - from io import StringIO - import select - import sys -+import socket - import time - try: - import unittest2 as unittest -@@ -30,6 +31,14 @@ import dns.rdatatype - import dns.resolver - from dns._compat import xrange - -+# Some tests require the internet to be available to run, so let's -+# skip those if it's not there. -+_network_available = True -+try: -+ socket.gethostbyname('dnspython.org') -+except socket.gaierror: -+ _network_available = False -+ - resolv_conf = u""" - /t/t - # comment 1 -@@ -86,18 +95,21 @@ class BaseResolverTests(object): - self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) - is None) - -+ @unittest.skipIf(not _network_available,"Internet not reachable") - def testZoneForName1(self): - name = dns.name.from_text('www.dnspython.org.') - ezname = dns.name.from_text('dnspython.org.') - zname = dns.resolver.zone_for_name(name) - self.failUnless(zname == ezname) - -+ @unittest.skipIf(not _network_available,"Internet not reachable") - def testZoneForName2(self): - name = dns.name.from_text('a.b.www.dnspython.org.') - ezname = dns.name.from_text('dnspython.org.') - zname = dns.resolver.zone_for_name(name) - self.failUnless(zname == ezname) - -+ @unittest.skipIf(not _network_available,"Internet not reachable") - def testZoneForName3(self): - name = dns.name.from_text('dnspython.org.') - ezname = dns.name.from_text('dnspython.org.') diff -Nru dnspython-1.14.0/debian/patches/series dnspython-1.15.0/debian/patches/series --- dnspython-1.14.0/debian/patches/series 2016-05-28 16:55:20.000000000 +0000 +++ dnspython-1.15.0/debian/patches/series 2016-10-24 11:53:17.000000000 +0000 @@ -1 +1 @@ -0001-Only-run-tests-in-tests-test_resolver.py-that-requir.patch +0001-Fix-file-write-location-in-testToFileFilename.patch diff -Nru dnspython-1.14.0/dns/_compat.py dnspython-1.15.0/dns/_compat.py --- dnspython-1.14.0/dns/_compat.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/_compat.py 2016-09-20 16:24:02.000000000 +0000 @@ -1,12 +1,13 @@ import sys - +import decimal +from decimal import Context if sys.version_info > (3,): long = int xrange = range else: - long = long - xrange = xrange + long = long # pylint: disable=long-builtin + xrange = xrange # pylint: disable=xrange-builtin # unicode / binary types if sys.version_info > (3,): @@ -14,8 +15,33 @@ binary_type = bytes string_types = (str,) unichr = chr + def maybe_decode(x): + return x.decode() + def maybe_encode(x): + return x.encode() else: - text_type = unicode + text_type = unicode # pylint: disable=unicode-builtin, undefined-variable binary_type = str - string_types = (basestring,) - unichr = unichr + string_types = ( + basestring, # pylint: disable=basestring-builtin, undefined-variable + ) + unichr = unichr # pylint: disable=unichr-builtin + def maybe_decode(x): + return x + def maybe_encode(x): + return x + + +def round_py2_compat(what): + """ + Python 2 and Python 3 use different rounding strategies in round(). This + function ensures that results are python2/3 compatible and backward + compatible with previous py2 releases + :param what: float + :return: rounded long + """ + d = Context( + prec=len(str(long(what))), # round to integer with max precision + rounding=decimal.ROUND_HALF_UP + ).create_decimal(str(what)) # str(): python 2.6 compat + return long(d) diff -Nru dnspython-1.14.0/dns/e164.py dnspython-1.15.0/dns/e164.py --- dnspython-1.14.0/dns/e164.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/e164.py 2016-09-20 16:24:02.000000000 +0000 @@ -56,7 +56,7 @@ """ if origin is not None: name = name.relativize(origin) - dlabels = [d for d in name.labels if (d.isdigit() and len(d) == 1)] + dlabels = [d for d in name.labels if d.isdigit() and len(d) == 1] if len(dlabels) != len(name.labels): raise dns.exception.SyntaxError('non-digit labels in ENUM domain name') dlabels.reverse() @@ -73,12 +73,13 @@ """ if resolver is None: resolver = dns.resolver.get_default_resolver() + e_nx = dns.resolver.NXDOMAIN() for domain in domains: if isinstance(domain, string_types): domain = dns.name.from_text(domain) qname = dns.e164.from_e164(number, domain) try: return resolver.query(qname, 'NAPTR') - except dns.resolver.NXDOMAIN: - pass - raise dns.resolver.NXDOMAIN + except dns.resolver.NXDOMAIN as e: + e_nx += e + raise e_nx diff -Nru dnspython-1.14.0/dns/entropy.py dnspython-1.15.0/dns/entropy.py --- dnspython-1.14.0/dns/entropy.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/entropy.py 2016-09-20 16:24:02.000000000 +0000 @@ -14,6 +14,7 @@ # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import os +import random import time from ._compat import long, binary_type try: @@ -33,21 +34,23 @@ import hashlib self.hash = hashlib.sha1() self.hash_len = 20 - except: + except ImportError: try: import sha self.hash = sha.new() self.hash_len = 20 - except: - import md5 + except ImportError: + import md5 # pylint: disable=import-error self.hash = md5.new() self.hash_len = 16 self.pool = bytearray(b'\0' * self.hash_len) if seed is not None: self.stir(bytearray(seed)) self.seeded = True + self.seed_pid = os.getpid() else: self.seeded = False + self.seed_pid = 0 def stir(self, entropy, already_locked=False): if not already_locked: @@ -64,19 +67,21 @@ self.lock.release() def _maybe_seed(self): - if not self.seeded: + if not self.seeded or self.seed_pid != os.getpid(): try: seed = os.urandom(16) - except: + except Exception: try: r = open('/dev/urandom', 'rb', 0) try: seed = r.read(16) finally: r.close() - except: + except Exception: seed = str(time.time()) self.seeded = True + self.seed_pid = os.getpid() + self.digest = None seed = bytearray(seed) self.stir(seed, True) @@ -114,14 +119,23 @@ else: rand = self.random_8 max = 255 - return (first + size * rand() // (max + 1)) + return first + size * rand() // (max + 1) pool = EntropyPool() +try: + system_random = random.SystemRandom() +except Exception: + system_random = None def random_16(): - return pool.random_16() - + if system_random is not None: + return system_random.randrange(0, 65536) + else: + return pool.random_16() def between(first, last): - return pool.random_between(first, last) + if system_random is not None: + return system_random.randrange(first, last + 1) + else: + return pool.random_between(first, last) diff -Nru dnspython-1.14.0/dns/exception.py dnspython-1.15.0/dns/exception.py --- dnspython-1.14.0/dns/exception.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/dns/exception.py 2016-09-20 19:13:40.000000000 +0000 @@ -23,14 +23,14 @@ It supports two basic modes of operation: a) Old/compatible mode is used if __init__ was called with - empty **kwargs. + empty **kwargs. In compatible mode all *args are passed to standard Python Exception class as before and all *args are printed by standard __str__ implementation. Class variable msg (or doc string if msg is None) is returned from str() if *args is empty. b) New/parametrized mode is used if __init__ was called with - non-empty **kwargs. + non-empty **kwargs. In the new mode *args has to be empty and all kwargs has to exactly match set in class variable self.supp_kwargs. All kwargs are stored inside self.kwargs and used in new __str__ implementation to construct @@ -45,8 +45,11 @@ def __init__(self, *args, **kwargs): self._check_params(*args, **kwargs) - self._check_kwargs(**kwargs) - self.kwargs = kwargs + if kwargs: + self.kwargs = self._check_kwargs(**kwargs) + self.msg = str(self) + else: + self.kwargs = dict() # defined but empty for old mode exceptions if self.msg is None: # doc string is better implicit message than empty string self.msg = self.__doc__ @@ -68,6 +71,7 @@ assert set(kwargs.keys()) == self.supp_kwargs, \ 'following set of keyword args is required: %s' % ( self.supp_kwargs) + return kwargs def _fmt_kwargs(self, **kwargs): """Format kwargs before printing them. diff -Nru dnspython-1.14.0/dns/grange.py dnspython-1.15.0/dns/grange.py --- dnspython-1.14.0/dns/grange.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/grange.py 2016-09-20 16:24:02.000000000 +0000 @@ -34,6 +34,10 @@ state = 0 # state 0 1 2 3 4 # x - y / z + + if text and text[0] == '-': + raise dns.exception.SyntaxError("Start cannot be a negative number") + for c in text: if c == '-' and state == 0: start = int(cur) @@ -49,7 +53,7 @@ raise dns.exception.SyntaxError("Could not parse %s" % (c)) if state in (1, 3): - raise dns.exception.SyntaxError + raise dns.exception.SyntaxError() if state == 2: stop = int(cur) diff -Nru dnspython-1.14.0/dns/hash.py dnspython-1.15.0/dns/hash.py --- dnspython-1.14.0/dns/hash.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/hash.py 2016-09-20 16:24:02.000000000 +0000 @@ -15,7 +15,6 @@ """Hashing backwards compatibility wrapper""" -import sys import hashlib diff -Nru dnspython-1.14.0/dns/inet.py dnspython-1.15.0/dns/inet.py --- dnspython-1.14.0/dns/inet.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/inet.py 2016-09-20 16:24:02.000000000 +0000 @@ -85,7 +85,7 @@ try: dns.ipv4.inet_aton(text) return AF_INET - except: + except Exception: try: dns.ipv6.inet_aton(text) return AF_INET6 @@ -102,10 +102,10 @@ """ try: first = ord(dns.ipv4.inet_aton(text)[0]) - return (first >= 224 and first <= 239) - except: + return first >= 224 and first <= 239 + except Exception: try: first = ord(dns.ipv6.inet_aton(text)[0]) - return (first == 255) - except: + return first == 255 + except Exception: raise ValueError diff -Nru dnspython-1.14.0/dns/ipv6.py dnspython-1.15.0/dns/ipv6.py --- dnspython-1.14.0/dns/ipv6.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/ipv6.py 2016-09-20 16:24:02.000000000 +0000 @@ -20,7 +20,7 @@ import dns.exception import dns.ipv4 -from ._compat import xrange, binary_type +from ._compat import xrange, binary_type, maybe_decode _leading_zero = re.compile(b'0+([0-9a-f]+)') @@ -89,7 +89,7 @@ b':'.join(chunks[best_start + best_len:]) else: hex = b':'.join(chunks) - return hex + return maybe_decode(hex) _v4_ending = re.compile(b'(.*):(\d+\.\d+\.\d+\.\d+)$') _colon_colon_start = re.compile(b'::.*') diff -Nru dnspython-1.14.0/dns/message.py dnspython-1.15.0/dns/message.py --- dnspython-1.14.0/dns/message.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/dns/message.py 2016-09-26 15:38:18.000000000 +0000 @@ -19,7 +19,6 @@ from io import StringIO import struct -import sys import time import dns.edns @@ -188,7 +187,7 @@ def __str__(self): return self.to_text() - def to_text(self, origin=None, relativize=True, **kw): + def to_text(self, origin=None, relativize=True, **kw): """Convert the message to text. The I{origin}, I{relativize}, and any other keyword @@ -899,7 +898,7 @@ raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError - except: + except Exception: rdclass = dns.rdataclass.IN # Type rdtype = dns.rdatatype.from_text(token.value) @@ -932,7 +931,7 @@ raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError - except: + except Exception: ttl = 0 # Class try: @@ -945,7 +944,7 @@ rdclass = self.zone_rdclass except dns.exception.SyntaxError: raise dns.exception.SyntaxError - except: + except Exception: rdclass = dns.rdataclass.IN # Type rdtype = dns.rdatatype.from_text(token.value) diff -Nru dnspython-1.14.0/dns/name.py dnspython-1.15.0/dns/name.py --- dnspython-1.14.0/dns/name.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/dns/name.py 2016-09-30 15:15:43.000000000 +0000 @@ -26,16 +26,21 @@ import sys import copy import encodings.idna +try: + import idna + have_idna_2008 = True +except ImportError: + have_idna_2008 = False import dns.exception import dns.wiredata -from ._compat import long, binary_type, text_type, unichr +from ._compat import long, binary_type, text_type, unichr, maybe_decode try: maxint = sys.maxint -except: - maxint = (1 << (8 * struct.calcsize("P"))) / 2 - 1 +except AttributeError: + maxint = (1 << (8 * struct.calcsize("P"))) // 2 - 1 NAMERELN_NONE = 0 NAMERELN_SUPERDOMAIN = 1 @@ -91,8 +96,151 @@ """An attempt was made to get the parent of the root name or the empty name.""" +class NoIDNA2008(dns.exception.DNSException): + + """IDNA 2008 processing was requested but the idna module is not + available.""" + + +class IDNAException(dns.exception.DNSException): + + """IDNA processing raised an exception.""" + + supp_kwargs = set(['idna_exception']) + fmt = "IDNA processing exception: {idna_exception}" + +class IDNACodec(object): + + """Abstract base class for IDNA encoder/decoders.""" + + def __init__(self): + pass + + def encode(self, label): + raise NotImplementedError + + def decode(self, label): + # We do not apply any IDNA policy on decode; we just + downcased = label.lower() + if downcased.startswith(b'xn--'): + try: + label = downcased[4:].decode('punycode') + except Exception as e: + raise IDNAException(idna_exception=e) + else: + label = maybe_decode(label) + return _escapify(label, True) + +class IDNA2003Codec(IDNACodec): + + """IDNA 2003 encoder/decoder.""" + + def __init__(self, strict_decode=False): + """Initialize the IDNA 2003 encoder/decoder. + @param 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. + @type strict_decode: bool + """ + super(IDNA2003Codec, self).__init__() + self.strict_decode = strict_decode + + def encode(self, label): + if label == '': + return b'' + try: + return encodings.idna.ToASCII(label) + except UnicodeError: + raise LabelTooLong + + def decode(self, label): + if not self.strict_decode: + return super(IDNA2003Codec, self).decode(label) + if label == b'': + return u'' + try: + return _escapify(encodings.idna.ToUnicode(label), True) + except Exception as e: + raise IDNAException(idna_exception=e) + +class IDNA2008Codec(IDNACodec): + + """IDNA 2008 encoder/decoder.""" + + def __init__(self, uts_46=False, transitional=False, + allow_pure_ascii=False, strict_decode=False): + """Initialize the IDNA 2008 encoder/decoder. + @param uts_46: If True, apply Unicode IDNA compatibility processing + as described in Unicode Technical Standard #46 + (U{http://unicode.org/reports/tr46/}). This parameter is only + meaningful if IDNA 2008 is in use. If False, do not apply + the mapping. The default is False + @type uts_46: bool + @param transitional: If True, use the "transitional" mode described + in Unicode Technical Standard #46. This parameter is only + meaningful if IDNA 2008 is in use. The default is False. + @type transitional: bool + @param 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 with starting with "_sip._tcp." and ending in an IDN + suffixm which would otherwise be disallowed. The default is False + @type allow_pure_ascii: bool + @param 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. + @type strict_decode: bool + """ + super(IDNA2008Codec, self).__init__() + self.uts_46 = uts_46 + self.transitional = transitional + self.allow_pure_ascii = allow_pure_ascii + self.strict_decode = strict_decode + + def is_all_ascii(self, label): + for c in label: + if ord(c) > 0x7f: + return False + return True + + def encode(self, label): + if label == '': + return b'' + if self.allow_pure_ascii and self.is_all_ascii(label): + return label.encode('ascii') + if not have_idna_2008: + raise NoIDNA2008 + try: + if self.uts_46: + label = idna.uts46_remap(label, False, self.transitional) + return idna.alabel(label) + except idna.IDNAError as e: + raise IDNAException(idna_exception=e) + + def decode(self, label): + if not self.strict_decode: + return super(IDNA2008Codec, self).decode(label) + if label == b'': + return u'' + if not have_idna_2008: + raise NoIDNA2008 + try: + if self.uts_46: + label = idna.uts46_remap(label, False, False) + return _escapify(idna.ulabel(label), True) + except idna.IDNAError as e: + raise IDNAException(idna_exception=e) + _escaped = bytearray(b'"().;\\@$') +IDNA_2003_Practical = IDNA2003Codec(False) +IDNA_2003_Strict = IDNA2003Codec(True) +IDNA_2003 = IDNA_2003_Practical +IDNA_2008_Practical = IDNA2008Codec(True, False, True, False) +IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False, False) +IDNA_2008_Strict = IDNA2008Codec(False, False, False, True) +IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False) +IDNA_2008 = IDNA_2008_Practical def _escapify(label, unicode_mode=False): """Escape the characters in label which need it. @@ -105,11 +253,10 @@ if isinstance(label, text_type): label = label.encode() for c in bytearray(label): - packed = struct.pack('!B', c).decode() if c in _escaped: - text += '\\' + packed + text += '\\' + chr(c) elif c > 0x20 and c < 0x7F: - text += packed + text += chr(c) else: text += '\\%03d' % c return text.encode() @@ -124,10 +271,9 @@ if c >= u'\x7f': text += c else: - text += u'\\%03d' % c + text += u'\\%03d' % ord(c) return text - def _validate_labels(labels): """Check for empty labels in the middle of a label sequence, labels that are too long, and for too many labels. @@ -356,7 +502,7 @@ return '' def __str__(self): - return self.to_text(False).decode() + return self.to_text(False) def to_text(self, omit_final_dot=False): """Convert name to text format. @@ -366,37 +512,44 @@ """ if len(self.labels) == 0: - return b'@' + return maybe_decode(b'@') if len(self.labels) == 1 and self.labels[0] == b'': - return b'.' + return maybe_decode(b'.') if omit_final_dot and self.is_absolute(): l = self.labels[:-1] else: l = self.labels s = b'.'.join(map(_escapify, l)) - return s + return maybe_decode(s) - def to_unicode(self, omit_final_dot=False): + def to_unicode(self, omit_final_dot=False, idna_codec=None): """Convert name to Unicode text format. IDN ACE labels are converted to Unicode. @param omit_final_dot: If True, don't emit the final dot (denoting the root label) for absolute names. The default is False. + @type omit_final_dot: bool + @param idna_codec: IDNA encoder/decoder. If None, the + IDNA_2003_Practical encoder/decoder is used. The IDNA_2003_Practical + decoder does not impose any policy, it just decodes punycode, so if + you don't want checking for compliance, you can use this decoder for + IDNA2008 as well. + @type idna_codec: dns.name.IDNA @rtype: string """ if len(self.labels) == 0: return u'@' - if len(self.labels) == 1 and self.labels[0] == '': + if len(self.labels) == 1 and self.labels[0] == b'': return u'.' if omit_final_dot and self.is_absolute(): l = self.labels[:-1] else: l = self.labels - s = u'.'.join([_escapify(encodings.idna.ToUnicode(x), True) - for x in l]) - return s + if idna_codec is None: + idna_codec = IDNA_2003_Practical + return u'.'.join([idna_codec.decode(x) for x in l]) def to_digestable(self, origin=None): """Convert name to a format suitable for digesting in hashes. @@ -489,9 +642,6 @@ def __getitem__(self, index): return self.labels[index] - def __getslice__(self, start, stop): - return self.labels[start:stop] - def __add__(self, other): return self.concatenate(other) @@ -584,11 +734,18 @@ empty = Name([]) -def from_unicode(text, origin=root): +def from_unicode(text, origin=root, idna_codec=None): """Convert unicode text into a Name object. Labels are encoded in IDN ACE form. + @param text: The text to convert into a name. + @type text: Unicode string + @param origin: The origin to append to non-absolute names. + @type origin: dns.name.Name + @param idna_codec: IDNA encoder/decoder. If None, the default IDNA 2003 + encoder/decoder is used. + @type idna_codec: dns.name.IDNA @rtype: dns.name.Name object """ @@ -601,6 +758,8 @@ escaping = False edigits = 0 total = 0 + if idna_codec is None: + idna_codec = IDNA_2003 if text == u'@': text = u'' if text: @@ -627,10 +786,7 @@ elif c in [u'.', u'\u3002', u'\uff0e', u'\uff61']: if len(label) == 0: raise EmptyLabel - try: - labels.append(encodings.idna.ToASCII(label)) - except UnicodeError: - raise LabelTooLong + labels.append(idna_codec.encode(label)) label = u'' elif c == u'\\': escaping = True @@ -641,10 +797,7 @@ if escaping: raise BadEscape if len(label) > 0: - try: - labels.append(encodings.idna.ToASCII(label)) - except UnicodeError: - raise LabelTooLong + labels.append(idna_codec.encode(label)) else: labels.append(b'') @@ -653,13 +806,21 @@ return Name(labels) -def from_text(text, origin=root): +def from_text(text, origin=root, idna_codec=None): """Convert text into a Name object. + + @param text: The text to convert into a name. + @type text: string + @param origin: The origin to append to non-absolute names. + @type origin: dns.name.Name + @param idna_codec: IDNA encoder/decoder. If None, the default IDNA 2003 + encoder/decoder is used. + @type idna_codec: dns.name.IDNA @rtype: dns.name.Name object """ if isinstance(text, text_type): - return from_unicode(text, origin) + return from_unicode(text, origin, idna_codec) if not isinstance(text, binary_type): raise ValueError("input to from_text() must be a string") if not (origin is None or isinstance(origin, Name)): diff -Nru dnspython-1.14.0/dns/opcode.py dnspython-1.15.0/dns/opcode.py --- dnspython-1.14.0/dns/opcode.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/opcode.py 2016-09-20 16:24:02.000000000 +0000 @@ -104,6 +104,4 @@ @rtype: bool """ - if (from_flags(flags) == UPDATE): - return True - return False + return from_flags(flags) == UPDATE diff -Nru dnspython-1.14.0/dns/query.py dnspython-1.15.0/dns/query.py --- dnspython-1.14.0/dns/query.py 2016-05-17 14:25:22.000000000 +0000 +++ dnspython-1.15.0/dns/query.py 2016-09-20 16:24:02.000000000 +0000 @@ -37,6 +37,9 @@ else: select_error = select.error +# Function used to create a socket. Can be overridden if needed in special +# situations. +socket_factory = socket.socket class UnexpectedSource(dns.exception.DNSException): @@ -173,7 +176,7 @@ if af is None: try: af = dns.inet.af_for_address(where) - except: + except Exception: af = dns.inet.AF_INET if af == dns.inet.AF_INET: destination = (where, port) @@ -223,7 +226,7 @@ wire = q.to_wire() (af, destination, source) = _destination_and_source(af, where, port, source, source_port) - s = socket.socket(af, socket.SOCK_DGRAM, 0) + s = socket_factory(af, socket.SOCK_DGRAM, 0) begin_time = None try: expiration = _compute_expiration(timeout) @@ -331,7 +334,7 @@ wire = q.to_wire() (af, destination, source) = _destination_and_source(af, where, port, source, source_port) - s = socket.socket(af, socket.SOCK_STREAM, 0) + s = socket_factory(af, socket.SOCK_STREAM, 0) begin_time = None try: expiration = _compute_expiration(timeout) @@ -435,9 +438,9 @@ if use_udp: if rdtype != dns.rdatatype.IXFR: raise ValueError('cannot do a UDP AXFR') - s = socket.socket(af, socket.SOCK_DGRAM, 0) + s = socket_factory(af, socket.SOCK_DGRAM, 0) else: - s = socket.socket(af, socket.SOCK_STREAM, 0) + s = socket_factory(af, socket.SOCK_STREAM, 0) s.setblocking(0) if source is not None: s.bind(source) diff -Nru dnspython-1.14.0/dns/rdata.py dnspython-1.15.0/dns/rdata.py --- dnspython-1.14.0/dns/rdata.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/dns/rdata.py 2016-09-20 16:24:02.000000000 +0000 @@ -28,7 +28,6 @@ from io import BytesIO import base64 import binascii -import struct import dns.exception import dns.name @@ -75,11 +74,7 @@ for i in range(0, len(line), chunksize)]).decode() -__escaped = { - '"': True, - '\\': True, -} - +__escaped = bytearray(b'"\\') def _escapify(qstring): """Escape the characters in a quoted string which need it. @@ -97,11 +92,10 @@ text = '' for c in qstring: - packed = struct.pack('!B', c).decode() - if packed in __escaped: - text += '\\' + packed + if c in __escaped: + text += '\\' + chr(c) elif c >= 0x20 and c < 0x7F: - text += packed + text += chr(c) else: text += '\\%03d' % c return text @@ -118,8 +112,8 @@ for i in xrange(len(what) - 1, -1, -1): if what[i] != 0: - break - return what[0: i + 1] + return what[0: i + 1] + return what[0:1] class Rdata(object): diff -Nru dnspython-1.14.0/dns/rdatatype.py dnspython-1.15.0/dns/rdatatype.py --- dnspython-1.14.0/dns/rdatatype.py 2016-05-23 22:12:33.000000000 +0000 +++ dnspython-1.15.0/dns/rdatatype.py 2016-09-20 19:54:45.000000000 +0000 @@ -96,6 +96,7 @@ ANY = 255 URI = 256 CAA = 257 +AVC = 258 TA = 32768 DLV = 32769 @@ -166,6 +167,7 @@ 'ANY': ANY, 'URI': URI, 'CAA': CAA, + 'AVC': AVC, 'TA': TA, 'DLV': DLV, } diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/AVC.py dnspython-1.15.0/dns/rdtypes/ANY/AVC.py --- dnspython-1.14.0/dns/rdtypes/ANY/AVC.py 1970-01-01 00:00:00.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/AVC.py 2016-09-20 19:53:55.000000000 +0000 @@ -0,0 +1,23 @@ +# Copyright (C) 2016 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import dns.rdtypes.txtbase + + +class AVC(dns.rdtypes.txtbase.TXTBase): + + """AVC record + + @see: U{http://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template}""" diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/CAA.py dnspython-1.15.0/dns/rdtypes/ANY/CAA.py --- dnspython-1.14.0/dns/rdtypes/ANY/CAA.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/CAA.py 2016-09-20 16:24:02.000000000 +0000 @@ -71,4 +71,3 @@ tag = wire[current: current + l] value = wire[current + l:current + rdlen - 2] return cls(rdclass, rdtype, flags, tag, value) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/CERT.py dnspython-1.15.0/dns/rdtypes/ANY/CERT.py --- dnspython-1.14.0/dns/rdtypes/ANY/CERT.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/CERT.py 2016-09-20 16:24:02.000000000 +0000 @@ -119,4 +119,3 @@ certificate = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/HINFO.py dnspython-1.15.0/dns/rdtypes/ANY/HINFO.py --- dnspython-1.14.0/dns/rdtypes/ANY/HINFO.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/HINFO.py 2016-09-20 16:24:02.000000000 +0000 @@ -82,4 +82,3 @@ raise dns.exception.FormError os = wire[current: current + l].unwrap() return cls(rdclass, rdtype, cpu, os) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/HIP.py dnspython-1.15.0/dns/rdtypes/ANY/HIP.py --- dnspython-1.14.0/dns/rdtypes/ANY/HIP.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/HIP.py 2016-09-20 16:24:02.000000000 +0000 @@ -53,7 +53,7 @@ for server in self.servers: servers.append(server.choose_relativity(origin, relativize)) if len(servers) > 0: - text += (u' ' + u' '.join(map(lambda x: x.to_unicode(), servers))) + text += (u' ' + u' '.join((x.to_unicode() for x in servers))) return u'%u %s %s%s' % (self.algorithm, hit, key, text) @classmethod diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/ISDN.py dnspython-1.15.0/dns/rdtypes/ANY/ISDN.py --- dnspython-1.14.0/dns/rdtypes/ANY/ISDN.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/ISDN.py 2016-09-20 16:24:02.000000000 +0000 @@ -95,4 +95,3 @@ else: subaddress = '' return cls(rdclass, rdtype, address, subaddress) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/LOC.py dnspython-1.15.0/dns/rdtypes/ANY/LOC.py --- dnspython-1.14.0/dns/rdtypes/ANY/LOC.py 2016-05-20 13:51:19.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/LOC.py 2016-09-20 16:24:02.000000000 +0000 @@ -13,11 +13,13 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import division + import struct import dns.exception import dns.rdata -from dns._compat import long, xrange +from dns._compat import long, xrange, round_py2_compat _pows = tuple(long(10**i) for i in range(0, 11)) @@ -47,7 +49,7 @@ what *= -1 else: sign = 1 - what = long(round(what * 3600000)) + what = round_py2_compat(what * 3600000) degrees = int(what // 3600000) what -= degrees * 3600000 minutes = int(what // 60000) @@ -136,16 +138,12 @@ def to_text(self, origin=None, relativize=True, **kw): if self.latitude[4] > 0: lat_hemisphere = 'N' - lat_degrees = self.latitude[0] else: lat_hemisphere = 'S' - lat_degrees = -1 * self.latitude[0] if self.longitude[4] > 0: long_hemisphere = 'E' - long_degrees = self.longitude[0] else: long_hemisphere = 'W' - long_degrees = -1 * self.longitude[0] text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % ( self.latitude[0], self.latitude[1], self.latitude[2], self.latitude[3], lat_hemisphere, diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/NSEC3PARAM.py dnspython-1.15.0/dns/rdtypes/ANY/NSEC3PARAM.py --- dnspython-1.14.0/dns/rdtypes/ANY/NSEC3PARAM.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/NSEC3PARAM.py 2016-09-20 16:24:02.000000000 +0000 @@ -86,4 +86,3 @@ if rdlen != 0: raise dns.exception.FormError return cls(rdclass, rdtype, algorithm, flags, iterations, salt) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/NSEC3.py dnspython-1.15.0/dns/rdtypes/ANY/NSEC3.py --- dnspython-1.14.0/dns/rdtypes/ANY/NSEC3.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/NSEC3.py 2016-09-20 16:24:02.000000000 +0000 @@ -189,4 +189,3 @@ windows.append((window, bitmap)) return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, windows) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/SSHFP.py dnspython-1.15.0/dns/rdtypes/ANY/SSHFP.py --- dnspython-1.14.0/dns/rdtypes/ANY/SSHFP.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/SSHFP.py 2016-09-20 16:24:02.000000000 +0000 @@ -75,4 +75,3 @@ rdlen -= 2 fingerprint = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], fingerprint) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/TLSA.py dnspython-1.15.0/dns/rdtypes/ANY/TLSA.py --- dnspython-1.14.0/dns/rdtypes/ANY/TLSA.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/TLSA.py 2016-09-20 16:24:02.000000000 +0000 @@ -80,4 +80,3 @@ rdlen -= 3 cert = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], cert) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/URI.py dnspython-1.15.0/dns/rdtypes/ANY/URI.py --- dnspython-1.14.0/dns/rdtypes/ANY/URI.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/URI.py 2016-09-20 16:24:02.000000000 +0000 @@ -78,4 +78,3 @@ current += rdlen return cls(rdclass, rdtype, priority, weight, target) - diff -Nru dnspython-1.14.0/dns/rdtypes/ANY/X25.py dnspython-1.15.0/dns/rdtypes/ANY/X25.py --- dnspython-1.14.0/dns/rdtypes/ANY/X25.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/ANY/X25.py 2016-09-20 16:24:02.000000000 +0000 @@ -62,4 +62,3 @@ raise dns.exception.FormError address = wire[current: current + l].unwrap() return cls(rdclass, rdtype, address) - diff -Nru dnspython-1.14.0/dns/rdtypes/dsbase.py dnspython-1.15.0/dns/rdtypes/dsbase.py --- dnspython-1.14.0/dns/rdtypes/dsbase.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/dsbase.py 2016-09-20 16:24:02.000000000 +0000 @@ -81,4 +81,3 @@ rdlen -= 4 digest = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], header[1], header[2], digest) - diff -Nru dnspython-1.14.0/dns/rdtypes/euibase.py dnspython-1.15.0/dns/rdtypes/euibase.py --- dnspython-1.14.0/dns/rdtypes/euibase.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/euibase.py 2016-09-20 16:24:02.000000000 +0000 @@ -17,6 +17,7 @@ import binascii import dns.rdata +from dns._compat import xrange class EUIBase(dns.rdata.Rdata): @@ -49,7 +50,7 @@ if len(text) != cls.text_len: raise dns.exception.SyntaxError( 'Input text must have %s characters' % cls.text_len) - expected_dash_idxs = range(2, cls.byte_len * 3 - 1, 3) + expected_dash_idxs = xrange(2, cls.byte_len * 3 - 1, 3) for i in expected_dash_idxs: if text[i] != '-': raise dns.exception.SyntaxError('Dash expected at position %s' @@ -68,4 +69,3 @@ def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): eui = wire[current:current + rdlen].unwrap() return cls(rdclass, rdtype, eui) - diff -Nru dnspython-1.14.0/dns/rdtypes/IN/AAAA.py dnspython-1.15.0/dns/rdtypes/IN/AAAA.py --- dnspython-1.14.0/dns/rdtypes/IN/AAAA.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/IN/AAAA.py 2016-09-20 16:24:02.000000000 +0000 @@ -51,4 +51,3 @@ address = dns.inet.inet_ntop(dns.inet.AF_INET6, wire[current: current + rdlen]) return cls(rdclass, rdtype, address) - diff -Nru dnspython-1.14.0/dns/rdtypes/IN/APL.py dnspython-1.15.0/dns/rdtypes/IN/APL.py --- dnspython-1.14.0/dns/rdtypes/IN/APL.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/IN/APL.py 2016-09-20 16:24:02.000000000 +0000 @@ -91,7 +91,7 @@ self.items = items def to_text(self, origin=None, relativize=True, **kw): - return ' '.join(map(lambda x: str(x), self.items)) + return ' '.join(map(str, self.items)) @classmethod def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): @@ -159,4 +159,3 @@ item = APLItem(header[0], negation, address, header[1]) items.append(item) return cls(rdclass, rdtype, items) - diff -Nru dnspython-1.14.0/dns/rdtypes/IN/A.py dnspython-1.15.0/dns/rdtypes/IN/A.py --- dnspython-1.14.0/dns/rdtypes/IN/A.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/IN/A.py 2016-09-20 16:24:02.000000000 +0000 @@ -50,4 +50,3 @@ def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): address = dns.ipv4.inet_ntoa(wire[current: current + rdlen]).decode() return cls(rdclass, rdtype, address) - diff -Nru dnspython-1.14.0/dns/rdtypes/IN/DHCID.py dnspython-1.15.0/dns/rdtypes/IN/DHCID.py --- dnspython-1.14.0/dns/rdtypes/IN/DHCID.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/IN/DHCID.py 2016-09-20 16:24:02.000000000 +0000 @@ -57,4 +57,3 @@ def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): data = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, data) - diff -Nru dnspython-1.14.0/dns/rdtypes/IN/IPSECKEY.py dnspython-1.15.0/dns/rdtypes/IN/IPSECKEY.py --- dnspython-1.14.0/dns/rdtypes/IN/IPSECKEY.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/IN/IPSECKEY.py 2016-09-20 16:24:02.000000000 +0000 @@ -146,4 +146,3 @@ key = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, header[0], gateway_type, header[2], gateway, key) - diff -Nru dnspython-1.14.0/dns/rdtypes/IN/NSAP.py dnspython-1.15.0/dns/rdtypes/IN/NSAP.py --- dnspython-1.14.0/dns/rdtypes/IN/NSAP.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/IN/NSAP.py 2016-09-20 16:24:02.000000000 +0000 @@ -56,4 +56,3 @@ def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): address = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, address) - diff -Nru dnspython-1.14.0/dns/rdtypes/IN/WKS.py dnspython-1.15.0/dns/rdtypes/IN/WKS.py --- dnspython-1.14.0/dns/rdtypes/IN/WKS.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/IN/WKS.py 2016-09-20 16:24:02.000000000 +0000 @@ -103,4 +103,3 @@ rdlen -= 5 bitmap = wire[current: current + rdlen].unwrap() return cls(rdclass, rdtype, address, protocol, bitmap) - diff -Nru dnspython-1.14.0/dns/rdtypes/txtbase.py dnspython-1.15.0/dns/rdtypes/txtbase.py --- dnspython-1.14.0/dns/rdtypes/txtbase.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rdtypes/txtbase.py 2016-09-20 16:24:02.000000000 +0000 @@ -88,4 +88,3 @@ rdlen -= l strings.append(s) return cls(rdclass, rdtype, strings) - diff -Nru dnspython-1.14.0/dns/renderer.py dnspython-1.15.0/dns/renderer.py --- dnspython-1.14.0/dns/renderer.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/dns/renderer.py 2016-09-20 16:24:02.000000000 +0000 @@ -19,7 +19,6 @@ import struct import random import time -import sys import dns.exception import dns.tsig diff -Nru dnspython-1.14.0/dns/resolver.py dnspython-1.15.0/dns/resolver.py --- dnspython-1.14.0/dns/resolver.py 2016-05-17 14:25:22.000000000 +0000 +++ dnspython-1.15.0/dns/resolver.py 2016-09-26 15:52:30.000000000 +0000 @@ -46,26 +46,66 @@ try: import winreg as _winreg except ImportError: - import _winreg + import _winreg # pylint: disable=import-error class NXDOMAIN(dns.exception.DNSException): """The DNS query name does not exist.""" - supp_kwargs = set(['qname']) + supp_kwargs = set(['qnames', 'responses']) + fmt = None # we have our own __str__ implementation + + def _check_kwargs(self, qnames, responses=None): + if not isinstance(qnames, (list, tuple, set)): + raise AttributeError("qnames must be a list, tuple or set") + if len(qnames) == 0: + raise AttributeError("qnames must contain at least one element") + if responses is None: + responses = {} + elif not isinstance(responses, dict): + raise AttributeError("responses must be a dict(qname=response)") + kwargs = dict(qnames=qnames, responses=responses) + return kwargs def __str__(self): - if 'qname' not in self.kwargs: + if 'qnames' not in self.kwargs: return super(NXDOMAIN, self).__str__() - - qname = self.kwargs['qname'] - msg = self.__doc__[:-1] - if isinstance(qname, (list, set)): - if len(qname) > 1: - msg = 'None of DNS query names exist' - qname = list(map(str, qname)) - else: - qname = qname[0] - return "%s: %s" % (msg, (str(qname))) + qnames = self.kwargs['qnames'] + if len(qnames) > 1: + msg = 'None of DNS query names exist' + else: + msg = self.__doc__[:-1] + qnames = ', '.join(map(str, qnames)) + return "%s: %s" % (msg, qnames) + + def canonical_name(self): + if not 'qnames' in self.kwargs: + raise TypeError("parametrized exception required") + IN = dns.rdataclass.IN + CNAME = dns.rdatatype.CNAME + cname = None + for qname in self.kwargs['qnames']: + response = self.kwargs['responses'][qname] + for answer in response.answer: + if answer.rdtype != CNAME or answer.rdclass != IN: + continue + cname = answer.items[0].target.to_text() + if cname is not None: + return dns.name.from_text(cname) + return self.kwargs['qnames'][0] + canonical_name = property(canonical_name, doc=( + "Return the unresolved canonical name.")) + + def __add__(self, e_nx): + """Augment by results from another NXDOMAIN exception.""" + qnames0 = list(self.kwargs.get('qnames', [])) + responses0 = dict(self.kwargs.get('responses', {})) + responses1 = e_nx.kwargs.get('responses', {}) + for qname1 in e_nx.kwargs.get('qnames', []): + if qname1 not in qnames0: + qnames0.append(qname1) + if qname1 in responses1: + responses0[qname1] = responses1[qname1] + return NXDOMAIN(qnames=qnames0, responses=responses0) class YXDOMAIN(dns.exception.DNSException): @@ -95,8 +135,9 @@ """All nameservers failed to answer the query. - @param errors: list of servers and respective errors - @type errors: [(server ip address, any object convertible to string)] + errors: list of servers and respective errors + The type of errors is + [(server ip address, any object convertible to string)]. Non-empty errors list will add explanatory message () """ @@ -231,10 +272,10 @@ raise AttributeError(attr) def __len__(self): - return len(self.rrset) + return self.rrset and len(self.rrset) or 0 def __iter__(self): - return iter(self.rrset) + return self.rrset and iter(self.rrset) or iter(tuple()) def __getitem__(self, i): return self.rrset[i] @@ -242,12 +283,6 @@ def __delitem__(self, i): del self.rrset[i] - def __getslice__(self, i, j): - return self.rrset[i:j] - - def __delslice__(self, i, j): - del self.rrset[i:j] - class Cache(object): @@ -397,7 +432,7 @@ """Initialize a DNS cache. @param max_size: The maximum number of nodes to cache; the default is - 100000. Must be > 1. + 100,000. Must be greater than 1. @type max_size: int """ self.data = {} @@ -544,6 +579,24 @@ POSIX systems and from the registry on Windows systems.) @type configure: bool""" + self.domain = None + self.nameservers = None + self.nameserver_ports = None + self.port = None + self.search = None + self.timeout = None + self.lifetime = None + self.keyring = None + self.keyname = None + self.keyalgorithm = None + self.edns = None + self.ednsflags = None + self.payload = None + self.cache = None + self.flags = None + self.retry_servfail = False + self.rotate = False + self.reset() if configure: if sys.platform == 'win32': @@ -659,7 +712,7 @@ """Extract DNS info from a registry key.""" try: servers, rtype = _winreg.QueryValueEx(key, 'NameServer') - except WindowsError: + except WindowsError: # pylint: disable=undefined-variable servers = None if servers: self._config_win32_nameservers(servers) @@ -667,12 +720,12 @@ dom, rtype = _winreg.QueryValueEx(key, 'Domain') if dom: self._config_win32_domain(dom) - except WindowsError: + except WindowsError: # pylint: disable=undefined-variable pass else: try: servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') - except WindowsError: + except WindowsError: # pylint: disable=undefined-variable servers = None if servers: self._config_win32_nameservers(servers) @@ -680,11 +733,11 @@ dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain') if dom: self._config_win32_domain(dom) - except WindowsError: + except WindowsError: # pylint: disable=undefined-variable pass try: search, rtype = _winreg.QueryValueEx(key, 'SearchList') - except WindowsError: + except WindowsError: # pylint: disable=undefined-variable search = None if search: self._config_win32_search(search) @@ -770,7 +823,7 @@ # Based on experimentation, bit 0x1 indicates that the # device is disabled. - return not (flags & 0x1) + return not flags & 0x1 finally: device_key.Close() @@ -786,7 +839,7 @@ (nte, ttype) = _winreg.QueryValueEx(interface_key, 'NTEContextList') return nte is not None - except WindowsError: + except WindowsError: # pylint: disable=undefined-variable return False def _compute_timeout(self, start): @@ -862,16 +915,18 @@ else: qnames_to_try.append(qname.concatenate(self.domain)) all_nxdomain = True + nxdomain_responses = {} start = time.time() - for qname in qnames_to_try: + _qname = None # make pylint happy + for _qname in qnames_to_try: if self.cache: - answer = self.cache.get((qname, rdtype, rdclass)) + answer = self.cache.get((_qname, rdtype, rdclass)) if answer is not None: if answer.rrset is None and raise_on_no_answer: - raise NoAnswer + raise NoAnswer(response=answer.response) else: return answer - request = dns.message.make_query(qname, rdtype, rdclass) + request = dns.message.make_query(_qname, rdtype, rdclass) if self.keyname is not None: request.use_tsig(self.keyring, self.keyname, algorithm=self.keyalgorithm) @@ -988,15 +1043,16 @@ backoff *= 2 time.sleep(sleep_time) if response.rcode() == dns.rcode.NXDOMAIN: + nxdomain_responses[_qname] = response continue all_nxdomain = False break if all_nxdomain: - raise NXDOMAIN(qname=qnames_to_try) - answer = Answer(qname, rdtype, rdclass, response, + raise NXDOMAIN(qnames=qnames_to_try, responses=nxdomain_responses) + answer = Answer(_qname, rdtype, rdclass, response, raise_on_no_answer) if self.cache: - self.cache.put((qname, rdtype, rdclass), answer) + self.cache.put((_qname, rdtype, rdclass), answer) return answer def use_tsig(self, keyring, keyname=None, @@ -1049,12 +1105,20 @@ def get_default_resolver(): """Get the default resolver, initializing it if necessary.""" - global default_resolver if default_resolver is None: - default_resolver = Resolver() + reset_default_resolver() return default_resolver +def reset_default_resolver(): + """Re-initialize default resolver. + + resolv.conf will be re-read immediatelly. + """ + global default_resolver + default_resolver = Resolver() + + def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, tcp=False, source=None, raise_on_no_answer=True, source_port=0): @@ -1147,13 +1211,13 @@ addr = dns.ipv6.inet_aton(ahost) v6addrs.append(host) canonical_name = host - except: + except Exception: try: # Is it a V4 address literal? addr = dns.ipv4.inet_aton(host) v4addrs.append(host) canonical_name = host - except: + except Exception: if flags & socket.AI_NUMERICHOST == 0: try: if family == socket.AF_INET6 or family == socket.AF_UNSPEC: @@ -1185,11 +1249,11 @@ port = 0 else: port = int(service) - except: + except Exception: if flags & socket.AI_NUMERICSERV == 0: try: port = socket.getservbyname(service) - except: + except Exception: pass if port is None: raise socket.gaierror(socket.EAI_NONAME) @@ -1264,7 +1328,7 @@ name = socket.gethostname() try: return _getnameinfo(_getaddrinfo(name, 80)[0][4])[0] - except: + except Exception: return name @@ -1289,7 +1353,7 @@ dns.ipv6.inet_aton(ip) sockaddr = (ip, 80, 0, 0) family = socket.AF_INET6 - except: + except Exception: sockaddr = (ip, 80) family = socket.AF_INET (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD) diff -Nru dnspython-1.14.0/dns/reversename.py dnspython-1.15.0/dns/reversename.py --- dnspython-1.14.0/dns/reversename.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/reversename.py 2016-09-20 16:24:02.000000000 +0000 @@ -51,7 +51,7 @@ else: parts = [x for x in str(binascii.hexlify(v6).decode())] origin = ipv6_reverse_domain - except: + except Exception: parts = ['%d' % byte for byte in bytearray(dns.ipv4.inet_aton(text))] origin = ipv4_reverse_domain diff -Nru dnspython-1.14.0/dns/rrset.py dnspython-1.15.0/dns/rrset.py --- dnspython-1.14.0/dns/rrset.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/rrset.py 2016-09-25 19:25:33.000000000 +0000 @@ -119,7 +119,8 @@ return dns.rdataset.from_rdata_list(self.ttl, list(self)) -def from_text_list(name, ttl, rdclass, rdtype, text_rdatas): +def from_text_list(name, ttl, rdclass, rdtype, text_rdatas, + idna_codec=None): """Create an RRset with the specified name, TTL, class, and type, and with the specified list of rdatas in text format. @@ -127,7 +128,7 @@ """ if isinstance(name, string_types): - name = dns.name.from_text(name, None) + name = dns.name.from_text(name, None, idna_codec=idna_codec) if isinstance(rdclass, string_types): rdclass = dns.rdataclass.from_text(rdclass) if isinstance(rdtype, string_types): @@ -150,7 +151,7 @@ return from_text_list(name, ttl, rdclass, rdtype, text_rdatas) -def from_rdata_list(name, ttl, rdatas): +def from_rdata_list(name, ttl, rdatas, idna_codec=None): """Create an RRset with the specified name and TTL, and with the specified list of rdata objects. @@ -158,7 +159,7 @@ """ if isinstance(name, string_types): - name = dns.name.from_text(name, None) + name = dns.name.from_text(name, None, idna_codec=idna_codec) if len(rdatas) == 0: raise ValueError("rdata list must not be empty") diff -Nru dnspython-1.14.0/dns/set.py dnspython-1.15.0/dns/set.py --- dnspython-1.14.0/dns/set.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/set.py 2016-09-20 16:24:02.000000000 +0000 @@ -232,12 +232,6 @@ def __delitem__(self, i): del self.items[i] - def __getslice__(self, i, j): - return self.items[i:j] - - def __delslice__(self, i, j): - del self.items[i:j] - def issubset(self, other): """Is I{self} a subset of I{other}? diff -Nru dnspython-1.14.0/dns/tokenizer.py dnspython-1.15.0/dns/tokenizer.py --- dnspython-1.14.0/dns/tokenizer.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/tokenizer.py 2016-09-20 16:24:02.000000000 +0000 @@ -96,7 +96,7 @@ return self.ttype == DELIMITER def is_eol_or_eof(self): - return (self.ttype == EOL or self.ttype == EOF) + return self.ttype == EOL or self.ttype == EOF def __eq__(self, other): if not isinstance(other, Token): @@ -332,7 +332,7 @@ self.skip_whitespace() continue elif c == ')': - if not self.multiline > 0: + if self.multiline <= 0: raise dns.exception.SyntaxError self.multiline -= 1 self.skip_whitespace() diff -Nru dnspython-1.14.0/dns/tsigkeyring.py dnspython-1.15.0/dns/tsigkeyring.py --- dnspython-1.14.0/dns/tsigkeyring.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/tsigkeyring.py 2016-09-20 16:24:02.000000000 +0000 @@ -15,6 +15,8 @@ """A place to store TSIG keys.""" +from dns._compat import maybe_decode, maybe_encode + import base64 import dns.name @@ -28,7 +30,7 @@ keyring = {} for keytext in textring: keyname = dns.name.from_text(keytext) - secret = base64.decodestring(textring[keytext]) + secret = base64.decodestring(maybe_encode(textring[keytext])) keyring[keyname] = secret return keyring @@ -40,7 +42,7 @@ textring = {} for keyname in keyring: - keytext = keyname.to_text() - secret = base64.encodestring(keyring[keyname]) + keytext = maybe_decode(keyname.to_text()) + secret = maybe_decode(base64.encodestring(keyring[keyname])) textring[keytext] = secret return textring diff -Nru dnspython-1.14.0/dns/tsig.py dnspython-1.15.0/dns/tsig.py --- dnspython-1.14.0/dns/tsig.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/tsig.py 2016-09-20 16:24:02.000000000 +0000 @@ -17,13 +17,12 @@ import hmac import struct -import sys import dns.exception import dns.hash import dns.rdataclass import dns.name -from ._compat import long, string_types +from ._compat import long, string_types, text_type class BadTime(dns.exception.DNSException): @@ -96,6 +95,8 @@ @raises NotImplementedError: I{algorithm} is not supported """ + if isinstance(other_data, text_type): + other_data = other_data.encode() (algorithm_name, digestmod) = get_algorithm(algorithm) if first: ctx = hmac.new(secret, digestmod=digestmod) @@ -193,7 +194,7 @@ (junk, our_mac, ctx) = sign(new_wire, keyname, secret, time, fudge, original_id, error, other_data, request_mac, ctx, multi, first, aname) - if (our_mac != mac): + if our_mac != mac: raise BadSignature return ctx diff -Nru dnspython-1.14.0/dns/version.py dnspython-1.15.0/dns/version.py --- dnspython-1.14.0/dns/version.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/dns/version.py 2016-09-20 16:24:02.000000000 +0000 @@ -16,7 +16,7 @@ """dnspython release version information.""" MAJOR = 1 -MINOR = 14 +MINOR = 15 MICRO = 0 RELEASELEVEL = 0x0f SERIAL = 0 diff -Nru dnspython-1.14.0/dns/wiredata.py dnspython-1.15.0/dns/wiredata.py --- dnspython-1.14.0/dns/wiredata.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/dns/wiredata.py 2016-09-20 16:24:02.000000000 +0000 @@ -15,6 +15,7 @@ """DNS Wire Data Helper""" +import sys import dns.exception from ._compat import binary_type, string_types @@ -26,12 +27,16 @@ # out what constant Python will use. -class _SliceUnspecifiedBound(str): +class _SliceUnspecifiedBound(binary_type): - def __getslice__(self, i, j): - return j + def __getitem__(self, key): + return key.stop + + if sys.version_info < (3,): + def __getslice__(self, i, j): # pylint: disable=getslice-method + return self.__getitem__(slice(i, j)) -_unspecified_bound = _SliceUnspecifiedBound('')[1:] +_unspecified_bound = _SliceUnspecifiedBound()[1:] class WireData(binary_type): @@ -40,26 +45,40 @@ def __getitem__(self, key): try: if isinstance(key, slice): - return WireData(super(WireData, self).__getitem__(key)) + # make sure we are not going outside of valid ranges, + # do stricter control of boundaries than python does + # by default + start = key.start + stop = key.stop + + if sys.version_info < (3,): + if stop == _unspecified_bound: + # handle the case where the right bound is unspecified + stop = len(self) + + if start < 0 or stop < 0: + raise dns.exception.FormError + # If it's not an empty slice, access left and right bounds + # to make sure they're valid + if start != stop: + super(WireData, self).__getitem__(start) + super(WireData, self).__getitem__(stop - 1) + else: + for index in (start, stop): + if index is None: + continue + elif abs(index) > len(self): + raise dns.exception.FormError + + return WireData(super(WireData, self).__getitem__( + slice(start, stop))) return bytearray(self.unwrap())[key] except IndexError: raise dns.exception.FormError - def __getslice__(self, i, j): - try: - if j == _unspecified_bound: - # handle the case where the right bound is unspecified - j = len(self) - if i < 0 or j < 0: - raise dns.exception.FormError - # If it's not an empty slice, access left and right bounds - # to make sure they're valid - if i != j: - super(WireData, self).__getitem__(i) - super(WireData, self).__getitem__(j - 1) - return WireData(super(WireData, self).__getslice__(i, j)) - except IndexError: - raise dns.exception.FormError + if sys.version_info < (3,): + def __getslice__(self, i, j): # pylint: disable=getslice-method + return self.__getitem__(slice(i, j)) def __iter__(self): i = 0 diff -Nru dnspython-1.14.0/dns/zone.py dnspython-1.15.0/dns/zone.py --- dnspython-1.14.0/dns/zone.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/dns/zone.py 2016-09-29 22:29:39.000000000 +0000 @@ -19,6 +19,7 @@ import sys import re +import os from io import BytesIO import dns.exception @@ -34,6 +35,9 @@ from ._compat import string_types, text_type +_py3 = sys.version_info > (3,) + + class BadZone(dns.exception.DNSException): """The DNS zone is malformed.""" @@ -150,16 +154,22 @@ del self.nodes[key] def __iter__(self): - return self.nodes.iterkeys() + return self.nodes.__iter__() def iterkeys(self): - return self.nodes.iterkeys() + if _py3: + return self.nodes.keys() + else: + return self.nodes.iterkeys() # pylint: disable=dict-iter-method def keys(self): return self.nodes.keys() def itervalues(self): - return self.nodes.itervalues() + if _py3: + return self.nodes.values() + else: + return self.nodes.itervalues() # pylint: disable=dict-iter-method def values(self): return self.nodes.values() @@ -489,18 +499,27 @@ @type nl: string or None """ - str_type = string_types + if isinstance(f, string_types): + f = open(f, 'wb') + want_close = True + else: + want_close = False + + # must be in this way, f.encoding may contain None, or even attribute + # may not be there + file_enc = getattr(f, 'encoding', None) + if file_enc is None: + file_enc = 'utf-8' if nl is None: - opts = 'wb' + nl_b = os.linesep.encode(file_enc) # binary mode, '\n' is not enough + nl = u'\n' + elif isinstance(nl, string_types): + nl_b = nl.encode(file_enc) else: - opts = 'wb' + nl_b = nl + nl = nl.decode() - if isinstance(f, str_type): - f = open(f, opts) - want_close = True - else: - want_close = False try: if sorted: names = list(self.keys()) @@ -511,11 +530,15 @@ l = self[n].to_text(n, origin=self.origin, relativize=relativize) if isinstance(l, text_type): - l = l.encode() - if nl is None: - f.write(l) - f.write('\n') + l_b = l.encode(file_enc) else: + l_b = l + l = l.decode() + + try: + f.write(l_b) + f.write(nl_b) + except TypeError: # textual mode f.write(l) f.write(nl) finally: @@ -649,7 +672,7 @@ raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError - except: + except Exception: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") @@ -722,7 +745,7 @@ base = 'd' if base != 'd': - raise NotImplemented + raise NotImplementedError() return mod, sign, offset, width, base @@ -768,7 +791,7 @@ raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError - except: + except Exception: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") @@ -778,7 +801,7 @@ token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError - except: + except Exception: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) diff -Nru dnspython-1.14.0/dnspython.egg-info/PKG-INFO dnspython-1.15.0/dnspython.egg-info/PKG-INFO --- dnspython-1.14.0/dnspython.egg-info/PKG-INFO 2016-05-27 16:13:32.000000000 +0000 +++ dnspython-1.15.0/dnspython.egg-info/PKG-INFO 2016-09-30 15:16:36.000000000 +0000 @@ -1,12 +1,12 @@ Metadata-Version: 1.1 Name: dnspython -Version: 1.14.0 +Version: 1.15.0 Summary: DNS toolkit Home-page: http://www.dnspython.org Author: Bob Halley Author-email: halley@dnspython.org License: BSD-like -Download-URL: http://www.dnspython.org/kits/1.14.0/dnspython-1.14.0.tar.gz +Download-URL: http://www.dnspython.org/kits/1.15.0/dnspython-1.15.0.tar.gz Description: dnspython is a DNS toolkit for Python. It supports almost all record types. It can be used for queries, zone transfers, and dynamic updates. It supports TSIG authenticated messages and EDNS0. diff -Nru dnspython-1.14.0/dnspython.egg-info/SOURCES.txt dnspython-1.15.0/dnspython.egg-info/SOURCES.txt --- dnspython-1.14.0/dnspython.egg-info/SOURCES.txt 2016-05-27 16:13:32.000000000 +0000 +++ dnspython-1.15.0/dnspython.egg-info/SOURCES.txt 2016-09-30 15:16:37.000000000 +0000 @@ -1,7 +1,6 @@ ChangeLog LICENSE MANIFEST.in -README.md setup.py dns/__init__.py dns/_compat.py @@ -48,6 +47,7 @@ dns/rdtypes/nsbase.py dns/rdtypes/txtbase.py dns/rdtypes/ANY/AFSDB.py +dns/rdtypes/ANY/AVC.py dns/rdtypes/ANY/CAA.py dns/rdtypes/ANY/CDNSKEY.py dns/rdtypes/ANY/CDS.py @@ -133,5 +133,6 @@ tests/test_set.py tests/test_tokenizer.py tests/test_update.py +tests/test_wiredata.py tests/test_zone.py tests/utest.py \ No newline at end of file diff -Nru dnspython-1.14.0/examples/e164.py dnspython-1.15.0/examples/e164.py --- dnspython-1.14.0/examples/e164.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/examples/e164.py 2016-09-20 16:24:02.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python +from __future__ import print_function + import dns.e164 n = dns.e164.from_e164("+1 555 1212") -print n -print dns.e164.to_e164(n) +print(n) +print(dns.e164.to_e164(n)) diff -Nru dnspython-1.14.0/examples/mx.py dnspython-1.15.0/examples/mx.py --- dnspython-1.14.0/examples/mx.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/examples/mx.py 2016-09-20 16:24:02.000000000 +0000 @@ -1,7 +1,9 @@ #!/usr/bin/env python +from __future__ import print_function + import dns.resolver answers = dns.resolver.query('nominum.com', 'MX') for rdata in answers: - print 'Host', rdata.exchange, 'has preference', rdata.preference + print('Host', rdata.exchange, 'has preference', rdata.preference) diff -Nru dnspython-1.14.0/examples/name.py dnspython-1.15.0/examples/name.py --- dnspython-1.14.0/examples/name.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/examples/name.py 2016-09-20 16:24:02.000000000 +0000 @@ -1,13 +1,15 @@ #!/usr/bin/env python +from __future__ import print_function + import dns.name n = dns.name.from_text('www.dnspython.org') o = dns.name.from_text('dnspython.org') -print n.is_subdomain(o) # True -print n.is_superdomain(o) # False -print n > o # True -rel = n.relativize(o) # rel is the relative name www +print(n.is_subdomain(o)) # True +print(n.is_superdomain(o)) # False +print(n > o) # True +rel = n.relativize(o) # rel is the relative name www n2 = rel + o -print n2 == n # True -print n.labels # ['www', 'dnspython', 'org', ''] +print(n2 == n) # True +print(n.labels) # ['www', 'dnspython', 'org', ''] diff -Nru dnspython-1.14.0/examples/reverse_name.py dnspython-1.15.0/examples/reverse_name.py --- dnspython-1.14.0/examples/reverse_name.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/examples/reverse_name.py 2016-09-20 16:24:02.000000000 +0000 @@ -1,6 +1,8 @@ #!/usr/bin/env python +from __future__ import print_function + import dns.reversename n = dns.reversename.from_address("127.0.0.1") -print n -print dns.reversename.to_address(n) +print(n) +print(dns.reversename.to_address(n)) diff -Nru dnspython-1.14.0/examples/reverse.py dnspython-1.15.0/examples/reverse.py --- dnspython-1.14.0/examples/reverse.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/examples/reverse.py 2016-09-20 16:24:02.000000000 +0000 @@ -16,6 +16,8 @@ # If this weren't a demo script, there'd be a way of specifying the # origin for each zone instead of constructing it from the filename. +from __future__ import print_function + import dns.zone import dns.ipv4 import os.path @@ -33,8 +35,8 @@ reverse_map[rdata.address] = [name.to_text()] keys = reverse_map.keys() -keys.sort(lambda a1, a2: cmp(dns.ipv4.inet_aton(a1), dns.ipv4.inet_aton(a2))) +keys.sort(key=dns.ipv4.inet_aton) for k in keys: v = reverse_map[k] v.sort() - print k, v + print(k, v) diff -Nru dnspython-1.14.0/examples/xfr.py dnspython-1.15.0/examples/xfr.py --- dnspython-1.14.0/examples/xfr.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/examples/xfr.py 2016-09-20 16:24:02.000000000 +0000 @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import print_function + import dns.query import dns.resolver import dns.zone @@ -11,4 +13,4 @@ names = z.nodes.keys() names.sort() for n in names: - print z[n].to_text(n) + print(z[n].to_text(n)) diff -Nru dnspython-1.14.0/examples/zonediff.py dnspython-1.15.0/examples/zonediff.py --- dnspython-1.14.0/examples/zonediff.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/examples/zonediff.py 2016-09-20 16:24:02.000000000 +0000 @@ -1,5 +1,5 @@ #!/usr/bin/env python -# +# # Small library and commandline tool to do logical diffs of zonefiles # ./zonediff -h gives you help output # @@ -11,7 +11,7 @@ # documentation for any purpose with or without fee is hereby granted, # provided that the above copyright notice and this permission notice # appear in all copies. -# +# # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -21,14 +21,15 @@ # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """See diff_zones.__doc__ for more information""" +from __future__ import print_function + __all__ = ['diff_zones', 'format_changes_plain', 'format_changes_html'] try: import dns.zone except ImportError: - import sys - sys.stderr.write("Please install dnspython") - sys.exit(1) + raise SystemExit("Please install dnspython") + def diff_zones(zone1, zone2, ignore_ttl=False, ignore_soa=False): """diff_zones(zone1, zone2, ignore_ttl=False, ignore_soa=False) -> changes @@ -37,7 +38,7 @@ If ignore_ttl is true, a node will not be added to this list if the only change is its TTL. - + If ignore_soa is true, a node will not be added to this list if the only changes is a change in a SOA Rdata set. @@ -87,20 +88,26 @@ ret = "--- %s\n+++ %s\n" % (oldf, newf) for name, old, new in changes: - ret += "@ %s\n" % name + ret += "@ %s\n" % name if not old: for r in new.rdatasets: - ret += "+ %s\n" % str(r).replace('\n','\n+ ') + ret += "+ %s\n" % str(r).replace('\n', '\n+ ') elif not new: for r in old.rdatasets: - ret += "- %s\n" % str(r).replace('\n','\n+ ') + ret += "- %s\n" % str(r).replace('\n', '\n+ ') else: for r in old.rdatasets: - if r not in new.rdatasets or (r.ttl != new.find_rdataset(r.rdclass, r.rdtype).ttl and not ignore_ttl): - ret += "- %s\n" % str(r).replace('\n','\n+ ') + if r not in new.rdatasets or ( + r.ttl != new.find_rdataset(r.rdclass, r.rdtype).ttl and + not ignore_ttl + ): + ret += "- %s\n" % str(r).replace('\n', '\n+ ') for r in new.rdatasets: - if r not in old.rdatasets or (r.ttl != old.find_rdataset(r.rdclass, r.rdtype).ttl and not ignore_ttl): - ret += "+ %s\n" % str(r).replace('\n','\n+ ') + if r not in old.rdatasets or ( + r.ttl != old.find_rdataset(r.rdclass, r.rdtype).ttl and + not ignore_ttl + ): + ret += "+ %s\n" % str(r).replace('\n', '\n+ ') return ret def format_changes_html(oldf, newf, changes, ignore_ttl=False): @@ -119,30 +126,43 @@ \n''' % (oldf, newf) for name, old, new in changes: - ret += ' \n %s\n' % name + ret += ' \n %s\n' % name if not old: for r in new.rdatasets: - ret += '  \n %s\n' % str(r).replace('\n','
') + ret += ( + '  \n' + ' %s\n' + ) % str(r).replace('\n', '
') elif not new: for r in old.rdatasets: - ret += ' %s\n  \n' % str(r).replace('\n','
') + ret += ( + ' %s\n' + '  \n' + ) % str(r).replace('\n', '
') else: ret += ' ' for r in old.rdatasets: - if r not in new.rdatasets or (r.ttl != new.find_rdataset(r.rdclass, r.rdtype).ttl and not ignore_ttl): - ret += str(r).replace('\n','
') + if r not in new.rdatasets or ( + r.ttl != new.find_rdataset(r.rdclass, r.rdtype).ttl and + not ignore_ttl + ): + ret += str(r).replace('\n', '
') ret += '\n' ret += ' ' for r in new.rdatasets: - if r not in old.rdatasets or (r.ttl != old.find_rdataset(r.rdclass, r.rdtype).ttl and not ignore_ttl): - ret += str(r).replace('\n','
') + if r not in old.rdatasets or ( + r.ttl != old.find_rdataset(r.rdclass, r.rdtype).ttl and + not ignore_ttl + ): + ret += str(r).replace('\n', '
') ret += '\n' ret += ' \n' return ret + ' \n' + # Make this module usable as a script too. -if __name__ == '__main__': - import optparse +def main(): + import argparse import subprocess import sys import traceback @@ -152,34 +172,26 @@ The differences shown will be logical differences, not textual differences. """ - p = optparse.OptionParser(usage=usage) - p.add_option('-s', '--ignore-soa', action="store_true", default=False, dest="ignore_soa", + p = argparse.ArgumentParser(usage=usage) + p.add_argument('-s', '--ignore-soa', action="store_true", default=False, dest="ignore_soa", help="Ignore SOA-only changes to records") - p.add_option('-t', '--ignore-ttl', action="store_true", default=False, dest="ignore_ttl", + p.add_argument('-t', '--ignore-ttl', action="store_true", default=False, dest="ignore_ttl", help="Ignore TTL-only changes to Rdata") - p.add_option('-T', '--traceback', action="store_true", default=False, dest="tracebacks", + p.add_argument('-T', '--traceback', action="store_true", default=False, dest="tracebacks", help="Show python tracebacks when errors occur") - p.add_option('-H', '--html', action="store_true", default=False, dest="html", + p.add_argument('-H', '--html', action="store_true", default=False, dest="html", help="Print HTML output") - p.add_option('-g', '--git', action="store_true", default=False, dest="use_git", + p.add_argument('-g', '--git', action="store_true", default=False, dest="use_git", help="Use git revisions instead of real files") - p.add_option('-b', '--bzr', action="store_true", default=False, dest="use_bzr", + p.add_argument('-b', '--bzr', action="store_true", default=False, dest="use_bzr", help="Use bzr revisions instead of real files") - p.add_option('-r', '--rcs', action="store_true", default=False, dest="use_rcs", + p.add_argument('-r', '--rcs', action="store_true", default=False, dest="use_rcs", help="Use rcs revisions instead of real files") opts, args = p.parse_args() opts.use_vc = opts.use_git or opts.use_bzr or opts.use_rcs def _open(what, err): - if isinstance(what, basestring): - # Open as normal file - try: - return open(what, 'rb') - except: - sys.stderr.write(err + "\n") - if opts.tracebacks: - traceback.print_exc() - else: + if isinstance(what, list): # Must be a list, open subprocess try: proc = subprocess.Popen(what, stdout=subprocess.PIPE) @@ -187,7 +199,15 @@ if proc.returncode == 0: return proc.stdout sys.stderr.write(err + "\n") - except: + except Exception: + sys.stderr.write(err + "\n") + if opts.tracebacks: + traceback.print_exc() + else: + # Open as normal file + try: + return open(what, 'rb') + except IOError: sys.stderr.write(err + "\n") if opts.tracebacks: traceback.print_exc() @@ -195,7 +215,7 @@ if not opts.use_vc and len(args) != 2: p.print_help() sys.exit(64) - if opts.use_vc and len(args) not in (2,3): + if opts.use_vc and len(args) not in (2, 3): p.print_help() sys.exit(64) @@ -213,7 +233,6 @@ oldn = "%s:%s" % (oldr, filename) newn = filename - old, new = None, None oldz, newz = None, None if opts.use_bzr: @@ -236,7 +255,7 @@ "Unable to retrieve revision %s of %s" % (newr, filename)) if not opts.use_vc: old = _open(oldn, "Unable to open %s" % oldn) - if not opts.use_vc or newr == None: + if not opts.use_vc or newr is None: new = _open(newn, "Unable to open %s" % newn) if not old or not new: @@ -244,13 +263,13 @@ # Parse the zones try: - oldz = dns.zone.from_file(old, origin = '.', check_origin=False) + oldz = dns.zone.from_file(old, origin='.', check_origin=False) except dns.exception.DNSException: sys.stderr.write("Incorrect zonefile: %s\n", old) if opts.tracebacks: traceback.print_exc() try: - newz = dns.zone.from_file(new, origin = '.', check_origin=False) + newz = dns.zone.from_file(new, origin='.', check_origin=False) except dns.exception.DNSException: sys.stderr.write("Incorrect zonefile: %s\n" % new) if opts.tracebacks: @@ -264,7 +283,10 @@ if not changes: sys.exit(0) if opts.html: - print format_changes_html(oldn, newn, changes, opts.ignore_ttl) + print(format_changes_html(oldn, newn, changes, opts.ignore_ttl)) else: - print format_changes_plain(oldn, newn, changes, opts.ignore_ttl) + print(format_changes_plain(oldn, newn, changes, opts.ignore_ttl)) sys.exit(1) + +if __name__ == '__main__': + main() diff -Nru dnspython-1.14.0/LICENSE dnspython-1.15.0/LICENSE --- dnspython-1.14.0/LICENSE 2011-07-09 14:05:21.000000000 +0000 +++ dnspython-1.15.0/LICENSE 2016-09-20 16:24:02.000000000 +0000 @@ -1,3 +1,5 @@ +ISC License + Copyright (C) 2001-2003 Nominum, Inc. Permission to use, copy, modify, and distribute this software and its diff -Nru dnspython-1.14.0/PKG-INFO dnspython-1.15.0/PKG-INFO --- dnspython-1.14.0/PKG-INFO 2016-05-27 16:13:32.000000000 +0000 +++ dnspython-1.15.0/PKG-INFO 2016-09-30 15:16:37.000000000 +0000 @@ -1,12 +1,12 @@ Metadata-Version: 1.1 Name: dnspython -Version: 1.14.0 +Version: 1.15.0 Summary: DNS toolkit Home-page: http://www.dnspython.org Author: Bob Halley Author-email: halley@dnspython.org License: BSD-like -Download-URL: http://www.dnspython.org/kits/1.14.0/dnspython-1.14.0.tar.gz +Download-URL: http://www.dnspython.org/kits/1.15.0/dnspython-1.15.0.tar.gz Description: dnspython is a DNS toolkit for Python. It supports almost all record types. It can be used for queries, zone transfers, and dynamic updates. It supports TSIG authenticated messages and EDNS0. diff -Nru dnspython-1.14.0/README.md dnspython-1.15.0/README.md --- dnspython-1.14.0/README.md 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,612 +0,0 @@ -dnspython [![Build Status](https://travis-ci.org/rthalley/dnspython.svg?branch=master)](https://travis-ci.org/rthalley/dnspython) - -## INTRODUCTION - -dnspython is a DNS toolkit for Python. It supports almost all record -types. It can be used for queries, zone transfers, and dynamic -updates. It supports TSIG authenticated messages and EDNS0. - -dnspython provides both high and low level access to DNS. The high -level classes perform queries for data of a given name, type, and -class, and return an answer set. The low level classes allow direct -manipulation of DNS zones, messages, names, and records. - -To see a few of the ways dnspython can be used, look in the examples/ -directory. - -dnspython originated at Nominum where it was developed to facilitate -the testing of DNS software. Nominum has generously allowed it to be -open sourced under a BSD-style license, and helps support its future -development by continuing to employ the author :). - -## INSTALLATION -- If you have pip installed, you can do this -`pip install dnspython` -- If not just download the source file and unzip it, then run this -`sudo python setup.py install` - -## ABOUT THIS RELEASE - -This is dnspython 1.14.0 - -New since 1.13.0: - - CSYNC RRs are now supported. - - dns/message.py (make_query): Setting any value which implies - EDNS will turn on EDNS if 'use_edns' has not been specified. - -Bugs fixed since 1.13.0: - - TSIG signature algorithm setting was broken by the Python 2 - and Python 3 code line merge. - - A bug in the LOC RR destroyed N/S and E/W distinctions within - a degree of the equator or prime merdian respectively. - - Misc. fixes to deal with fallout from the Python 2 & 3 merge. - [issue #156], [issue #157], [issue #158], [issue #159], - [issue #160]. - - Running with python optimization on caused issues when - stripped docstrings were referenced. [issue #154] - - dns.zone.from_text() erroneously required the zone to be provided. - [issue #153] - -New since 1.12.0: - - Dnspython now uses a single source for Python 2 and Python 3, - eliminating the painful merging between the Python 2 and Python 3 - branches. Thank you so much to Arthur Gautier for taking on this - challenge and making it work! It was a big job! - - Support for Python older than 2.6 dropped. - - Support for Python older than 3.3 dropped. - - Zone origin can be specified as a string. - - A rich string representation for all DNSExceptions. - - setuptools has replaced distutils - - Added support for CAA, CDS, CDNSKEY, EUI48, EUI64, and URI RR - types. - - Names now support the pickle protocol. - - Ports can be specified per-nameserver in the stub resolver. - -Bugs fixed since 1.12.0: - - A number of Unicode name bugs have been fixed. - - resolv.conf processing now rejects lines with too few tokens. - - NameDicts now keep the max-depth value correct, and update properly. - -New since 1.11.1: - - Added dns.zone.to_text(). - - Added support for "options rotate" in /etc/resolv.conf. - - dns.rdtypes.ANY.DNSKEY now has helpers functions to convert - between the numeric form of the flags and a set of - human-friendly strings - - The reverse name of an IPv6 mapped IPv4 address is now in the - IPv4 reverse namespace. - - The test system can now run the tests without requiring - dnspython to be installed. - - Preliminary Elliptic Curve DNSSEC Validation (requires ecdsa module) - -Bugs fixed since 1.11.1: - - dnspython raised an exception when reading a masterfile starting - with leading whitespace - - dnspython was affected by a python slicing API bug present on - 64-bit windows. - - Unicode escaping was applied at the wrong time. - - RRSIG to_text() did not respect the relativize setting. - - APL RRs with zero rdlength were rejected. - - The tokenizer could put back an unescaped token. - - Making a response to a message signed with TSIG was broken. - - The IXFR state machine didn't handle long IXFR diffs. - -New since 1.11.0: - - Nothing - -Bugs fixed since 1.11.0: - - dns.resolver.Resolver erroneously referred to 'retry_servfail' - instead of 'self.retry_servfail'. - - dns.tsigkeyring.to_text() would fail trying to convert the - keyname to text. - - Multi-message TSIGs were broken for algorithms other than - HMAC-MD5 because we weren't passing the right digest module to - the HMAC code. - - dns.dnssec._find_candidate_keys() tried to extract the key - from the wrong variable name. - - $GENERATE tests were not backward compatible with python 2.4. - -New since 1.10.0: - - $GENERATE support - - TLSA RR support - - Added set_flags() method to dns.resolver.Resolver - -Bugs fixed since 1.10.0: - - Names with offsets >= 2^14 are no longer added to the compression - table. - - The "::" syntax is not used to shorten a single 16-bit section of - the text form an IPv6 address. - - Caches are now locked. - - YXDOMAIN is raised if seen by the resolver. - - Empty rdatasets are not printed. - - DNSKEY key tags are no longer assumed to be unique. - -New since 1.9.4: - - Added dns.resolver.LRUCache. In this cache implementation, - the cache size is limited to a user-specified number of nodes, - and when adding a new node to a full cache the least-recently - used node is removed. If you're crawling the web or otherwise - doing lots of resolutions and you are using a cache, switching - to the LRUCache is recommended. - - dns.resolver.query() will try TCP if a UDP response is - truncated. - - The python socket module's DNS methods can be now be overridden - with implementations that use dnspython's resolver. - - Old DNSSEC types KEY, NXT, and SIG have been removed. - - Whitespace is allowed in SSHFP fingerprints. - - Origin checking in dns.zone.from_xfr() can be disabled. - - Trailing junk checking can be disabled. - - A source port can be specified when creating a resolver query. - - All EDNS values may now be specified to dns.message.make_query(). - -Bugs fixed since 1.9.4: - - IPv4 and IPv6 address processing is now stricter. - - Bounds checking of slices in rdata wire processing is now more - strict, and bounds errors (e.g. we got less data than was - expected) now raise dns.exception.FormError rather than - IndexError. - - Specifying a source port without specifying source used to - have no effect, but now uses the wildcard address and the - specified port. - -New since 1.9.3: - - Nothing. - -Bugs fixed since 1.9.3: - - The rdata _wire_cmp() routine now handles relative names. - - The SIG RR implementation was missing 'import struct'. - -New since 1.9.2: - - A boolean parameter, 'raise_on_no_answer', has been added to - the query() methods. In no-error, no-data situations, this - parameter determines whether NoAnswer should be raised or not. - If True, NoAnswer is raised. If False, then an Answer() - object with a None rrset will be returned. - - Resolver Answer() objects now have a canonical_name field. - - Rdata now have a __hash__ method. - -Bugs fixed since 1.9.2: - - Dnspython was erroneously doing case-insensitive comparisons - of the names in NSEC and RRSIG RRs. - - We now use "is" and not "==" when testing what section an RR - is in. - - The resolver now disallows metaqueries. - -New since 1.9.1: - - Nothing. - -Bugs fixed since 1.9.1: - - The dns.dnssec module didn't work at all due to missing - imports that escaped detection in testing because the test - suite also did the imports. The third time is the charm! - -New since 1.9.0: - - Nothing. - -Bugs fixed since 1.9.0: - - The dns.dnssec module didn't work with DSA due to namespace - contamination from a "from"-style import. - -New since 1.8.0: - - dnspython now uses poll() instead of select() when available. - - Basic DNSSEC validation can be done using dns.dnsec.validate() - and dns.dnssec.validate_rrsig() if you have PyCrypto 2.3 or - later installed. Complete secure resolution is not yet - available. - - Added key_id() to the DNSSEC module, which computes the DNSSEC - key id of a DNSKEY rdata. - - Added make_ds() to the DNSSEC module, which returns the DS RR - for a given DNSKEY rdata. - - dnspython now raises an exception if HMAC-SHA284 or - HMAC-SHA512 are used with a Python older than 2.5.2. (Older - Pythons do not compute the correct value.) - - Symbolic constants are now available for TSIG algorithm names. - -Bugs fixed since 1.8.0 - - dns.resolver.zone_for_name() didn't handle a query response - with a CNAME or DNAME correctly in some cases. - - When specifying rdata types and classes as text, Unicode - strings may now be used. - - Hashlib compatibility issues have been fixed. - - dns.message now imports dns.edns. - - The TSIG algorithm value was passed incorrectly to use_tsig() - in some cases. - -New since 1.7.1: - - Support for hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384 - and hmac-sha512 has been contributed by Kevin Chen. - - The tokenizer's tokens are now Token objects instead of (type, - value) tuples. - -Bugs fixed since 1.7.1: - - Escapes in masterfiles now work correctly. Previously they - were only working correctly when the text involved was part of - a domain name. - - When constructing a DDNS update, if the present() method was - used with a single rdata, a zero TTL was not added. - - The entropy pool needed locking to be thread safe. - - The entropy pool's reading of /dev/random could cause - dnspython to block. - - The entropy pool did buffered reads, potentially consuming more - randomness than we needed. - - The entropy pool did not seed with high quality randomness on - Windows. - - SRV records were compared incorrectly. - - In the e164 query function, the resolver parameter was not - used. - -New since 1.7.0: - - Nothing - -Bugs fixed since 1.7.0: - - The 1.7.0 kitting process inadvertently omitted the code for the - DLV RR. - - Negative DDNS prerequisites are now handled correctly. - -New since 1.6.0: - - Rdatas now have a to_digestable() method, which returns the - DNSSEC canonical form of the rdata, suitable for use in - signature computations. - - The NSEC3, NSEC3PARAM, DLV, and HIP RR types are now supported. - - An entropy module has been added and is used to randomize query ids. - - EDNS0 options are now supported. - - UDP IXFR is now supported. - - The wire format parser now has a 'one_rr_per_rrset' mode, which - suppresses the usual coalescing of all RRs of a given type into a - single RRset. - - Various helpful DNSSEC-related constants are now defined. - - The resolver's query() method now has an optional 'source' parameter, - allowing the source IP address to be specified. - -Bugs fixed since 1.6.0: - - On Windows, the resolver set the domain incorrectly. - - DS RR parsing only allowed one Base64 chunk. - - TSIG validation didn't always use absolute names. - - NSEC.to_text() only printed the last window. - - We did not canonicalize IPv6 addresses before comparing them; we - would thus treat equivalent but different textual forms, e.g. - "1:00::1" and "1::1" as being non-equivalent. - - If the peer set a TSIG error, we didn't raise an exception. - - Some EDNS bugs in the message code have been fixed (see the ChangeLog - for details). - -New since 1.5.0: - Added dns.inet.is_multicast(). - -Bugs fixed since 1.5.0: - - If select() raises an exception due to EINTR, we should just - select() again. - - If the queried address is a multicast address, then don't - check that the address of the response is the same as the - address queried. - - NAPTR comparisons didn't compare the preference field due to a - typo. - - Testing of whether a Windows NIC is enabled now works on Vista - thanks to code contributed by Paul Marks. - -New since 1.4.0: - - Answer objects now support more of the python sequence - protocol, forwarding the requests to the answer rrset. - E.g. "for a in answer" is equivalent to "for a in - answer.rrset", "answer[i]" is equivalent to "answer.rrset[i]", - and "answer[i:j]" is equivalent to "answer.rrset[i:j]". - - Making requests using EDNS, including indicating DNSSEC awareness, - is now easier. For example, you can now say: - - q = dns.message.make_query('www.dnspython.org', 'MX', - want_dnssec=True) - - dns.query.xfr() can now be used for IXFR. - - Support has been added for the DHCID, IPSECKEY, and SPF RR types. - - UDP messages from unexpected sources can now be ignored by - setting ignore_unexpected to True when calling dns.query.udp. - -Bugs fixed since 1.4.0: - - If /etc/resolv.conf didn't exist, we raised an exception - instead of simply using the default resolver configuration. - - In dns.resolver.Resolver._config_win32_fromkey(), we were - passing the wrong variable to self._config_win32_search(). - -New since 1.3.5: - - You can now convert E.164 numbers to/from their ENUM name - forms: - - >>> import dns.e164 - >>> n = dns.e164.from_e164("+1 555 1212") - >>> n - - >>> dns.e164.to_e164(n) - '+15551212' - - You can now convert IPv4 and IPv6 address to/from their - corresponding DNS reverse map names: - - >>> import dns.reversename - >>> n = dns.reversename.from_address("127.0.0.1") - >>> n - - >>> dns.reversename.to_address(n) - '127.0.0.1' - - You can now convert between Unicode strings and their IDN ACE - form: - - >>> n = dns.name.from_text(u'les-\u00e9l\u00e8ves.example.') - >>> n - - >>> n.to_unicode() - u'les-\xe9l\xe8ves.example.' - - The origin parameter to dns.zone.from_text() and dns.zone.to_text() - is now optional. If not specified, the origin will be taken from - the first $ORIGIN statement in the master file. - - Sanity checking of a zone can be disabled; this is useful when - working with files which are zone fragments. - -Bugs fixed since 1.3.5: - - The correct delimiter was not used when retrieving the - list of nameservers from the registry in certain versions of - windows. - - The floating-point version of latitude and longitude in LOC RRs - (float_latitude and float_longitude) had incorrect signs for - south latitudes and west longitudes. - - BIND 8 TTL syntax is now accepted in all TTL-like places (i.e. - SOA fields refresh, retry, expire, and minimum; SIG/RRSIG - field original_ttl). - - TTLs are now bounds checked when their text form is parsed, - and their values must be in the closed interval [0, 2^31 - 1]. - -New since 1.3.4: - - In the resolver, if time goes backward a little bit, ignore - it. - - zone_for_name() has been added to the resolver module. It - returns the zone which is authoritative for the specified - name, which is handy for dynamic update. E.g. - - import dns.resolver - print dns.resolver.zone_for_name('www.dnspython.org') - - will output "dnspython.org." and - - print dns.resolver.zone_for_name('a.b.c.d.e.f.example.') - - will output ".". - - The default resolver can be fetched with the - get_default_resolver() method. - - You can now get the parent (immediate superdomain) of a name - by using the parent() method. - - Zone.iterate_rdatasets() and Zone.iterate_rdatas() now have - a default rdtype of dns.rdatatype.ANY like the documentation - says. - - A Dynamic DNS example, ddns.py, has been added. - -New since 1.3.3: - - The source address and port may now be specified when calling - dns.query.{udp,tcp,xfr}. - - The resolver now does exponential backoff each time it runs - through all of the nameservers. - - Rcodes which indicate a nameserver is likely to be a - "permanent failure" for a query cause the nameserver to be removed - from the mix for that query. - -New since 1.3.2: - - dns.message.Message.find_rrset() now uses an index, vastly - improving the from_wire() performance of large messages such - as zone transfers. - - Added dns.message.make_response(), which creates a skeletal - response for the specified query. - - Added opcode() and set_opcode() convenience methods to the - dns.message.Message class. Added the request_payload - attribute to the Message class. - - The 'file' parameter of dns.name.Name.to_wire() is now - optional; if omitted, the wire form will be returned as the - value of the function. - - dns.zone.from_xfr() in relativization mode incorrectly set - zone.origin to the empty name. - - The masterfile parser incorrectly rejected TXT records where a - value was not quoted. - -New since 1.3.1: - - The NSEC format doesn't allow specifying types by number, so - we shouldn't either. (Using the unknown type format is still - OK though.) - - The resolver wasn't catching dns.exception.Timeout, so a timeout - erroneously caused the whole resolution to fail instead of just - going on to the next server. - - The renderer module didn't import random, causing an exception - to be raised if a query id wasn't provided when a Renderer was - created. - - The conversion of LOC milliseconds values from text to binary was - incorrect if the length of the milliseconds string was not 3. - -New since 1.3.0: - - Added support for the SSHFP type. - -New since 1.2.0: - - Added support for new DNSSEC types RRSIG, NSEC, and DNSKEY. - -This release fixes all known bugs. - -See the ChangeLog file for more detailed information on changes since -the prior release. - - -## REQUIREMENTS - -Python 2.6 or later. - - -## HOME PAGE - -For the latest in releases, documentation, and information, visit the -dnspython home page at - - http://www.dnspython.org/ - - - -## DOCUMENTATION - -Documentation is sparse at the moment. Use pydoc, or read the HTML -documentation at the dnspython home page, or download the HTML -documentation. - - -## BUG REPORTS - -Bug reports may be sent to bugs@dnspython.org - - -## MAILING LISTS - -A number of mailing lists are available. Visit the dnspython home -page to subscribe or unsubscribe. diff -Nru dnspython-1.14.0/setup.py dnspython-1.15.0/setup.py --- dnspython-1.14.0/setup.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/setup.py 2016-09-20 16:24:02.000000000 +0000 @@ -18,7 +18,7 @@ import sys from setuptools import setup -version = '1.14.0' +version = '1.15.0' kwargs = { 'name' : 'dnspython', diff -Nru dnspython-1.14.0/tests/example dnspython-1.15.0/tests/example --- dnspython-1.14.0/tests/example 2016-05-23 22:11:29.000000000 +0000 +++ dnspython-1.15.0/tests/example 2016-09-20 19:57:38.000000000 +0000 @@ -196,3 +196,4 @@ caa05 CAA 0 issue "ca.example.net; policy=ev" caa06 CAA 128 tbs "Unknown" csync0 CSYNC 12345 0 A MX RRSIG NSEC TYPE1234 +avc01 AVC "app-name:WOLFGANG|app-class:OAM|business=yes" diff -Nru dnspython-1.14.0/tests/example1.good dnspython-1.15.0/tests/example1.good --- dnspython-1.14.0/tests/example1.good 2016-05-23 22:17:57.000000000 +0000 +++ dnspython-1.15.0/tests/example1.good 2016-09-20 19:58:05.000000000 +0000 @@ -14,6 +14,7 @@ afsdb02 3600 IN AFSDB 65535 . apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28 apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 +avc01 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes" b 300 IN CNAME foo.net. c 300 IN A 73.80.65.49 caa01 3600 IN CAA 0 issue "ca.example.net" diff -Nru dnspython-1.14.0/tests/example2.good dnspython-1.15.0/tests/example2.good --- dnspython-1.14.0/tests/example2.good 2016-05-23 22:17:33.000000000 +0000 +++ dnspython-1.15.0/tests/example2.good 2016-09-20 19:58:05.000000000 +0000 @@ -14,6 +14,7 @@ afsdb02.example. 3600 IN AFSDB 65535 . apl01.example. 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28 apl02.example. 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 +avc01.example. 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes" b.example. 300 IN CNAME foo.net. c.example. 300 IN A 73.80.65.49 caa01.example. 3600 IN CAA 0 issue "ca.example.net" diff -Nru dnspython-1.14.0/tests/example3.good dnspython-1.15.0/tests/example3.good --- dnspython-1.14.0/tests/example3.good 2016-05-23 22:17:15.000000000 +0000 +++ dnspython-1.15.0/tests/example3.good 2016-09-20 19:58:05.000000000 +0000 @@ -14,6 +14,7 @@ afsdb02 3600 IN AFSDB 65535 . apl01 3600 IN APL 1:192.168.32.0/21 !1:192.168.38.0/28 apl02 3600 IN APL 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8 +avc01 3600 IN AVC "app-name:WOLFGANG|app-class:OAM|business=yes" b 300 IN CNAME foo.net. c 300 IN A 73.80.65.49 caa01 3600 IN CAA 0 issue "ca.example.net" diff -Nru dnspython-1.14.0/tests/test_bugs.py dnspython-1.15.0/tests/test_bugs.py --- dnspython-1.14.0/tests/test_bugs.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_bugs.py 2016-09-20 16:24:02.000000000 +0000 @@ -41,7 +41,7 @@ def test_TTL_bounds_check(self): def bad(): - ttl = dns.ttl.from_text("2147483648") + dns.ttl.from_text("2147483648") self.failUnlessRaises(dns.ttl.BadTTL, bad) def test_empty_NSEC3_window(self): @@ -58,7 +58,7 @@ def test_CAA_from_wire(self): rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CAA, - u'0 issue "ca.example.net"'); + u'0 issue "ca.example.net"') f = BytesIO() rdata.to_wire(f) wire = f.getvalue() diff -Nru dnspython-1.14.0/tests/test_dnssec.py dnspython-1.15.0/tests/test_dnssec.py --- dnspython-1.14.0/tests/test_dnssec.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/tests/test_dnssec.py 2016-09-20 16:24:02.000000000 +0000 @@ -13,11 +13,19 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + try: import unittest2 as unittest except ImportError: import unittest +try: + import Crypto.Util.number # pylint: disable=unused-import + import_ok = True +except ImportError: + import_ok = False + import dns.dnssec import dns.name import dns.rdata @@ -25,26 +33,34 @@ import dns.rdatatype import dns.rrset +# pylint: disable=line-too-long + abs_dnspython_org = dns.name.from_text('dnspython.org') -abs_keys = { abs_dnspython_org : - dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'DNSKEY', - '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', - '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') - } - -abs_keys_duplicate_keytag = { abs_dnspython_org : - dns.rrset.from_text('dnspython.org.', 3600, 'IN', 'DNSKEY', - '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', - '256 3 5 AwEAAdSSg++++THIS/IS/NOT/THE/CORRECT/KEY++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ AaOSydAF', - '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') - } - -rel_keys = { dns.name.empty : - dns.rrset.from_text('@', 3600, 'IN', 'DNSKEY', - '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', - '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF') - } +abs_keys = { + abs_dnspython_org: dns.rrset.from_text( + 'dnspython.org.', 3600, 'IN', 'DNSKEY', + '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', + '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF' + ) +} + +abs_keys_duplicate_keytag = { + abs_dnspython_org: dns.rrset.from_text( + 'dnspython.org.', 3600, 'IN', 'DNSKEY', + '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', + '256 3 5 AwEAAdSSg++++THIS/IS/NOT/THE/CORRECT/KEY++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ AaOSydAF', + '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF' + ) +} + +rel_keys = { + dns.name.empty: dns.rrset.from_text( + '@', 3600, 'IN', 'DNSKEY', + '257 3 5 AwEAAenVTr9L1OMlL1/N2ta0Qj9LLLnnmFWIr1dJoAsWM9BQfsbV7kFZ XbAkER/FY9Ji2o7cELxBwAsVBuWn6IUUAJXLH74YbC1anY0lifjgt29z SwDzuB7zmC7yVYZzUunBulVW4zT0tg1aePbpVL2EtTL8VzREqbJbE25R KuQYHZtFwG8S4iBxJUmT2Bbd0921LLxSQgVoFXlQx/gFV2+UERXcJ5ce iX6A6wc02M/pdg/YbJd2rBa0MYL3/Fz/Xltre0tqsImZGxzi6YtYDs45 NC8gH+44egz82e2DATCVM1ICPmRDjXYTLldQiWA2ZXIWnK0iitl5ue24 7EsWJefrIhE=', + '256 3 5 AwEAAdSSghOGjU33IQZgwZM2Hh771VGXX05olJK49FxpSyuEAjDBXY58 LGU9R2Zgeecnk/b9EAhFu/vCV9oECtiTCvwuVAkt9YEweqYDluQInmgP NGMJCKdSLlnX93DkjDw8rMYv5dqXCuSGPlKChfTJOLQxIAxGloS7lL+c 0CTZydAF' + ) +} when = 1290250287 @@ -76,11 +92,13 @@ abs_example = dns.name.from_text('example') -abs_dsa_keys = { abs_example : - dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', - '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X', - '256 3 3 CJE1yb9YRQiw5d2xZrMUMR+cGCTt1bp1KDCefmYKmS+Z1+q9f42ETVhx JRiQwXclYwmxborzIkSZegTNYIV6mrYwbNB27Q44c3UGcspb3PiOw5TC jNPRYEcdwGvDZ2wWy+vkSV/S9tHXY8O6ODiE6abZJDDg/RnITyi+eoDL R3KZ5n/V1f1T1b90rrV6EewhBGQJpQGDogaXb2oHww9Tm6NfXyo7SoMM pbwbzOckXv+GxRPJIQNSF4D4A9E8XCksuzVVdE/0lr37+uoiAiPia38U 5W2QWe/FJAEPLjIp2eTzf0TrADc1pKP1wrA2ASpdzpm/aX3IB5RPp8Ew S9U72eBFZJAUwg635HxJVxH1maG6atzorR566E+e0OZSaxXS9o1o6QqN 3oPlYLGPORDiExilKfez3C/x/yioOupW9K5eKF0gmtaqrHX0oq9s67f/ RIM2xVaKHgG9Vf2cgJIZkhv7sntujr+E4htnRmy9P9BxyFxsItYxPI6Z bzygHAZpGhlI/7ltEGlIwKxyTK3ZKBm67q7B') - } +abs_dsa_keys = { + abs_example: dns.rrset.from_text( + 'example.', 86400, 'IN', 'DNSKEY', + '257 3 3 CI3nCqyJsiCJHTjrNsJOT4RaszetzcJPYuoH3F9ZTVt3KJXncCVR3bwn 1w0iavKljb9hDlAYSfHbFCp4ic/rvg4p1L8vh5s8ToMjqDNl40A0hUGQ Ybx5hsECyK+qHoajilUX1phYSAD8d9WAGO3fDWzUPBuzR7o85NiZCDxz yXuNVfni0uhj9n1KYhEO5yAbbruDGN89wIZcxMKuQsdUY2GYD93ssnBv a55W6XRABYWayKZ90WkRVODLVYLSn53Pj/wwxGH+XdhIAZJXimrZL4yl My7rtBsLMqq8Ihs4Tows7LqYwY7cp6y/50tw6pj8tFqMYcPUjKZV36l1 M/2t5BVg3i7IK61Aidt6aoC3TDJtzAxg3ZxfjZWJfhHjMJqzQIfbW5b9 q1mjFsW5EUv39RaNnX+3JWPRLyDqD4pIwDyqfutMsdk/Py3paHn82FGp CaOg+nicqZ9TiMZURN/XXy5JoXUNQ3RNvbHCUiPUe18KUkY6mTfnyHld 1l9YCWmzXQVClkx/hOYxjJ4j8Ife58+Obu5X', + '256 3 3 CJE1yb9YRQiw5d2xZrMUMR+cGCTt1bp1KDCefmYKmS+Z1+q9f42ETVhx JRiQwXclYwmxborzIkSZegTNYIV6mrYwbNB27Q44c3UGcspb3PiOw5TC jNPRYEcdwGvDZ2wWy+vkSV/S9tHXY8O6ODiE6abZJDDg/RnITyi+eoDL R3KZ5n/V1f1T1b90rrV6EewhBGQJpQGDogaXb2oHww9Tm6NfXyo7SoMM pbwbzOckXv+GxRPJIQNSF4D4A9E8XCksuzVVdE/0lr37+uoiAiPia38U 5W2QWe/FJAEPLjIp2eTzf0TrADc1pKP1wrA2ASpdzpm/aX3IB5RPp8Ew S9U72eBFZJAUwg635HxJVxH1maG6atzorR566E+e0OZSaxXS9o1o6QqN 3oPlYLGPORDiExilKfez3C/x/yioOupW9K5eKF0gmtaqrHX0oq9s67f/ RIM2xVaKHgG9Vf2cgJIZkhv7sntujr+E4htnRmy9P9BxyFxsItYxPI6Z bzygHAZpGhlI/7ltEGlIwKxyTK3ZKBm67q7B' + ) +} abs_dsa_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400') @@ -102,11 +120,13 @@ when3 = 1379801800 -abs_ecdsa256_keys = { abs_example : - dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', - "256 3 13 +3ss1sCpdARVA61DJigEsL/8quo2a8MszKtn2gkkfxgzFs8S2UHtpb4N fY+XFmNW+JK6MsCkI3jHYN8eEQUgMw==", - "257 3 13 eJCEVH7AS3wnoaQpaNlAXH0W8wxymtT9P6P3qjN2ZCV641ED8pF7wZ5V yWfOpgTs6oaZevbJgehl/GaRPUgVyQ==") - } +abs_ecdsa256_keys = { + abs_example: dns.rrset.from_text( + 'example.', 86400, 'IN', 'DNSKEY', + "256 3 13 +3ss1sCpdARVA61DJigEsL/8quo2a8MszKtn2gkkfxgzFs8S2UHtpb4N fY+XFmNW+JK6MsCkI3jHYN8eEQUgMw==", + "257 3 13 eJCEVH7AS3wnoaQpaNlAXH0W8wxymtT9P6P3qjN2ZCV641ED8pF7wZ5V yWfOpgTs6oaZevbJgehl/GaRPUgVyQ==" + ) +} abs_ecdsa256_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', 'ns1.example. hostmaster.example. 4 10800 3600 604800 86400') @@ -119,11 +139,13 @@ when4 = 1379804850 -abs_ecdsa384_keys = { abs_example : - dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY', - "256 3 14 1bG8qWviKNXQX3BIuG6/T5jrP1FISiLW/8qGF6BsM9DQtWYhhZUA3Owr OAEiyHAhQwjkN2kTvWiAYoPN80Ii+5ff9/atzY4F9W50P4l75Dj9PYrL HN/hLUgWMNVc9pvA", - "257 3 14 mSub2n0KRt6u2FaD5XJ3oQu0R4XvB/9vUJcyW6+oo0y+KzfQeTdkf1ro ZMVKoyWXW9zUKBYGJpMUIdbAxzrYi7f5HyZ3yDpBFz1hw9+o3CX+gtgb +RyhHfJDwwFXBid9") - } +abs_ecdsa384_keys = { + abs_example: dns.rrset.from_text( + 'example.', 86400, 'IN', 'DNSKEY', + "256 3 14 1bG8qWviKNXQX3BIuG6/T5jrP1FISiLW/8qGF6BsM9DQtWYhhZUA3Owr OAEiyHAhQwjkN2kTvWiAYoPN80Ii+5ff9/atzY4F9W50P4l75Dj9PYrL HN/hLUgWMNVc9pvA", + "257 3 14 mSub2n0KRt6u2FaD5XJ3oQu0R4XvB/9vUJcyW6+oo0y+KzfQeTdkf1ro ZMVKoyWXW9zUKBYGJpMUIdbAxzrYi7f5HyZ3yDpBFz1hw9+o3CX+gtgb +RyhHfJDwwFXBid9" + ) +} abs_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA', 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400') @@ -134,34 +156,36 @@ abs_ecdsa384_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG', "SOA 14 1 86400 20130929021229 20130921230729 63571 example. CrnCu34EeeRz0fEhL9PLlwjpBKGYW8QjBjFQTwd+ViVLRAS8tNkcDwQE NhSV89NEjj7ze1a/JcCfcJ+/mZgnvH4NHLNg3Tf6KuLZsgs2I4kKQXEk 37oIHravPEOlGYNI") +@unittest.skipUnless(import_ok, "skipping DNSSEC tests because pycrypto is not" + " installed") class DNSSECValidatorTestCase(unittest.TestCase): - @unittest.skipIf(not dns.dnssec._have_pycrypto, - "PyCrypto cannot be imported") + @unittest.skipUnless(dns.dnssec._have_pycrypto, + "PyCrypto cannot be imported") def testAbsoluteRSAGood(self): dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys, None, when) - @unittest.skipIf(not dns.dnssec._have_pycrypto, - "PyCrypto cannot be imported") + @unittest.skipUnless(dns.dnssec._have_pycrypto, + "PyCrypto cannot be imported") def testDuplicateKeytag(self): dns.dnssec.validate(abs_soa, abs_soa_rrsig, abs_keys_duplicate_keytag, None, when) - @unittest.skipIf(not dns.dnssec._have_pycrypto, - "PyCrypto cannot be imported") + @unittest.skipUnless(dns.dnssec._have_pycrypto, + "PyCrypto cannot be imported") def testAbsoluteRSABad(self): def bad(): dns.dnssec.validate(abs_other_soa, abs_soa_rrsig, abs_keys, None, when) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) - @unittest.skipIf(not dns.dnssec._have_pycrypto, - "PyCrypto cannot be imported") + @unittest.skipUnless(dns.dnssec._have_pycrypto, + "PyCrypto cannot be imported") def testRelativeRSAGood(self): dns.dnssec.validate(rel_soa, rel_soa_rrsig, rel_keys, abs_dnspython_org, when) - @unittest.skipIf(not dns.dnssec._have_pycrypto, - "PyCrypto cannot be imported") + @unittest.skipUnless(dns.dnssec._have_pycrypto, + "PyCrypto cannot be imported") def testRelativeRSABad(self): def bad(): dns.dnssec.validate(rel_other_soa, rel_soa_rrsig, rel_keys, @@ -172,14 +196,14 @@ ds = dns.dnssec.make_ds(abs_dnspython_org, sep_key, 'SHA256') self.failUnless(ds == good_ds) - @unittest.skipIf(not dns.dnssec._have_pycrypto, - "PyCrypto cannot be imported") + @unittest.skipUnless(dns.dnssec._have_pycrypto, + "PyCrypto cannot be imported") def testAbsoluteDSAGood(self): dns.dnssec.validate(abs_dsa_soa, abs_dsa_soa_rrsig, abs_dsa_keys, None, when2) - @unittest.skipIf(not dns.dnssec._have_pycrypto, - "PyCrypto cannot be imported") + @unittest.skipUnless(dns.dnssec._have_pycrypto, + "PyCrypto cannot be imported") def testAbsoluteDSABad(self): def bad(): dns.dnssec.validate(abs_other_dsa_soa, abs_dsa_soa_rrsig, @@ -194,28 +218,28 @@ ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256') self.failUnless(ds == example_ds_sha256) - @unittest.skipIf(not dns.dnssec._have_ecdsa, - "python ECDSA cannot be imported") + @unittest.skipUnless(dns.dnssec._have_ecdsa, + "python ECDSA cannot be imported") def testAbsoluteECDSA256Good(self): dns.dnssec.validate(abs_ecdsa256_soa, abs_ecdsa256_soa_rrsig, abs_ecdsa256_keys, None, when3) - @unittest.skipIf(not dns.dnssec._have_ecdsa, - "python ECDSA cannot be imported") + @unittest.skipUnless(dns.dnssec._have_ecdsa, + "python ECDSA cannot be imported") def testAbsoluteECDSA256Bad(self): def bad(): dns.dnssec.validate(abs_other_ecdsa256_soa, abs_ecdsa256_soa_rrsig, abs_ecdsa256_keys, None, when3) self.failUnlessRaises(dns.dnssec.ValidationFailure, bad) - @unittest.skipIf(not dns.dnssec._have_ecdsa, - "python ECDSA cannot be imported") + @unittest.skipUnless(dns.dnssec._have_ecdsa, + "python ECDSA cannot be imported") def testAbsoluteECDSA384Good(self): dns.dnssec.validate(abs_ecdsa384_soa, abs_ecdsa384_soa_rrsig, abs_ecdsa384_keys, None, when4) - @unittest.skipIf(not dns.dnssec._have_ecdsa, - "python ECDSA cannot be imported") + @unittest.skipUnless(dns.dnssec._have_ecdsa, + "python ECDSA cannot be imported") def testAbsoluteECDSA384Bad(self): def bad(): dns.dnssec.validate(abs_other_ecdsa384_soa, abs_ecdsa384_soa_rrsig, @@ -224,13 +248,4 @@ if __name__ == '__main__': - import_ok = False - try: - import Crypto.Util.number - import_ok = True - except: - pass - if import_ok: - unittest.main() - else: - print('skipping DNSSEC tests because pycrypto is not installed') + unittest.main() diff -Nru dnspython-1.14.0/tests/test_exceptions.py dnspython-1.15.0/tests/test_exceptions.py --- dnspython-1.14.0/tests/test_exceptions.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_exceptions.py 2016-09-20 16:24:02.000000000 +0000 @@ -13,7 +13,6 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import binascii try: import unittest2 as unittest except ImportError: diff -Nru dnspython-1.14.0/tests/test_flags.py dnspython-1.15.0/tests/test_flags.py --- dnspython-1.14.0/tests/test_flags.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_flags.py 2016-09-20 16:24:02.000000000 +0000 @@ -25,7 +25,7 @@ class FlagsTestCase(unittest.TestCase): def test_rcode1(self): - self.failUnless(dns.rcode.from_text('FORMERR') == dns.rcode.FORMERR) + self.failUnless(dns.rcode.from_text('FORMERR') == dns.rcode.FORMERR) def test_rcode2(self): self.failUnless(dns.rcode.to_text(dns.rcode.FORMERR) == "FORMERR") @@ -41,10 +41,10 @@ self.failUnless(dns.rcode.from_flags(0, 0x01000000) == \ dns.rcode.BADVERS) - def test_rcode6(self): + def test_rcode7(self): self.failUnless(dns.rcode.from_flags(5, 0) == dns.rcode.REFUSED) - def test_rcode7(self): + def test_rcode8(self): def bad(): dns.rcode.to_flags(4096) self.failUnlessRaises(ValueError, bad) diff -Nru dnspython-1.14.0/tests/test_generate.py dnspython-1.15.0/tests/test_generate.py --- dnspython-1.14.0/tests/test_generate.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_generate.py 2016-09-20 16:24:02.000000000 +0000 @@ -16,8 +16,6 @@ import sys sys.path.insert(0, '../') # Force the local project to be *the* dns -import filecmp -import os try: import unittest2 as unittest except ImportError: @@ -36,7 +34,6 @@ pp = pprint.PrettyPrinter(indent=2) -import pdb example_text = """$TTL 1h $ORIGIN 0.0.192.IN-ADDR.ARPA. $GENERATE 1-2 0 CNAME SERVER$.EXAMPLE. @@ -145,12 +142,12 @@ def testFromText(self): def bad(): - z = dns.zone.from_text(example_text, 'example.', relativize=True) + dns.zone.from_text(example_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoSOA, bad) def testFromText1(self): def bad(): - z = dns.zone.from_text(example_text1, 'example.', relativize=True) + dns.zone.from_text(example_text1, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoSOA, bad) def testIterateAllRdatas2(self): diff -Nru dnspython-1.14.0/tests/test_grange.py dnspython-1.15.0/tests/test_grange.py --- dnspython-1.14.0/tests/test_grange.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_grange.py 2016-09-20 16:24:02.000000000 +0000 @@ -16,8 +16,6 @@ import sys sys.path.insert(0, '../') -import filecmp -import os try: import unittest2 as unittest except ImportError: @@ -27,9 +25,6 @@ import dns.exception import dns.grange -import pdb - - class GRangeTestCase(unittest.TestCase): @@ -85,7 +80,7 @@ dns.grange.from_text('%s-%d/%d' % (start, stop, step)) self.assertRaises(dns.exception.SyntaxError, bad) - def testFailFromText2(self): + def testFailFromText3(self): def bad(): start = 1 stop = 4 diff -Nru dnspython-1.14.0/tests/test_message.py dnspython-1.15.0/tests/test_message.py --- dnspython-1.14.0/tests/test_message.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_message.py 2016-09-20 16:24:02.000000000 +0000 @@ -13,7 +13,6 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import os try: import unittest2 as unittest except ImportError: @@ -141,7 +140,7 @@ dns.rdatatype.A, '10.0.0.%d' % i) q.additional.append(rrset) - w = q.to_wire(max_size=512) + q.to_wire(max_size=512) self.failUnlessRaises(dns.exception.TooBig, bad) def test_answer1(self): @@ -152,20 +151,20 @@ def test_TrailingJunk(self): def bad(): badwire = goodwire + b'\x00' - m = dns.message.from_wire(badwire) + dns.message.from_wire(badwire) self.failUnlessRaises(dns.message.TrailingJunk, bad) def test_ShortHeader(self): def bad(): badwire = b'\x00' * 11 - m = dns.message.from_wire(badwire) + dns.message.from_wire(badwire) self.failUnlessRaises(dns.message.ShortHeader, bad) def test_RespondingToResponse(self): def bad(): q = dns.message.make_query('foo', 'A') r1 = dns.message.make_response(q) - r2 = dns.message.make_response(r1) + dns.message.make_response(r1) self.failUnlessRaises(dns.exception.FormError, bad) def test_ExtendedRcodeSetting(self): diff -Nru dnspython-1.14.0/tests/test_namedict.py dnspython-1.15.0/tests/test_namedict.py --- dnspython-1.14.0/tests/test_namedict.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_namedict.py 2016-09-20 16:24:02.000000000 +0000 @@ -57,18 +57,18 @@ def testLookup5(self): def bad(): n = dns.name.from_text('a.b.c.') - (k, v) = self.ndict.get_deepest_match(n) + self.ndict.get_deepest_match(n) self.failUnlessRaises(KeyError, bad) def testLookup6(self): def bad(): - (k, v) = self.ndict.get_deepest_match(dns.name.empty) + self.ndict.get_deepest_match(dns.name.empty) self.failUnlessRaises(KeyError, bad) def testLookup7(self): self.ndict[dns.name.empty] = 100 n = dns.name.from_text('a.b.c.') - (k, v) = self.ndict.get_deepest_match(n) + v = self.ndict.get_deepest_match(n)[1] self.failUnless(v == 100) def testLookup8(self): @@ -98,7 +98,7 @@ def testRelLookup7(self): self.rndict[dns.name.empty] = 100 n = dns.name.from_text('a.b.c', None) - (k, v) = self.rndict.get_deepest_match(n) + v = self.rndict.get_deepest_match(n)[1] self.failUnless(v == 100) if __name__ == '__main__': diff -Nru dnspython-1.14.0/tests/test_name.py dnspython-1.15.0/tests/test_name.py --- dnspython-1.14.0/tests/test_name.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_name.py 2016-09-29 15:23:07.000000000 +0000 @@ -1,3 +1,4 @@ +# -*- coding: utf-8 # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. # # Permission to use, copy, modify, and distribute this software and its @@ -13,18 +14,22 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + try: import unittest2 as unittest except ImportError: import unittest from io import BytesIO -import socket import dns.name import dns.reversename import dns.e164 +# pylint: disable=line-too-long + + class NameTestCase(unittest.TestCase): def setUp(self): self.origin = dns.name.from_text('example.') @@ -51,7 +56,7 @@ def testFromTextAbs1(self): n = dns.name.from_text('foo.bar.') - self.assertEqual(n.labels,(b'foo', b'bar', b'')) + self.assertEqual(n.labels, (b'foo', b'bar', b'')) def testTortureFromText(self): good = [ @@ -81,14 +86,14 @@ ] for t in good: try: - n = dns.name.from_text(t) - except: + dns.name.from_text(t) + except Exception: self.fail("good test '%s' raised an exception" % t) for t in bad: caught = False try: - n = dns.name.from_text(t) - except: + dns.name.from_text(t) + except Exception: caught = True if not caught: self.fail("bad test '%s' did not raise an exception" % t) @@ -112,7 +117,7 @@ def testAbs3(self): self.failUnless(self.origin.is_absolute()) - def testAbs3(self): + def testAbs4(self): n = dns.name.from_text('foo', origin=None) self.failUnless(not n.is_absolute()) @@ -202,40 +207,53 @@ def testToText1(self): n = dns.name.from_text('FOO.bar', origin=self.origin) t = n.to_text() - self.assertEqual(t, b'FOO.bar.example.') + self.assertEqual(t, 'FOO.bar.example.') def testToText2(self): n = dns.name.from_text('FOO.bar', origin=self.origin) t = n.to_text(True) - self.assertEqual(t, b'FOO.bar.example') + self.assertEqual(t, 'FOO.bar.example') def testToText3(self): n = dns.name.from_text('FOO.bar', origin=None) t = n.to_text() - self.assertEqual(t, b'FOO.bar') + self.assertEqual(t, 'FOO.bar') def testToText4(self): t = dns.name.empty.to_text() - self.assertEqual(t, b'@') + self.assertEqual(t, '@') def testToText5(self): t = dns.name.root.to_text() - self.assertEqual(t, b'.') + self.assertEqual(t, '.') def testToText6(self): n = dns.name.from_text('FOO bar', origin=None) t = n.to_text() - self.assertEqual(t, br'FOO\032bar') + self.assertEqual(t, r'FOO\032bar') def testToText7(self): n = dns.name.from_text(r'FOO\.bar', origin=None) t = n.to_text() - self.assertEqual(t, b'FOO\.bar') + self.assertEqual(t, 'FOO\.bar') def testToText8(self): n = dns.name.from_text(r'\070OO\.bar', origin=None) t = n.to_text() - self.assertEqual(t, b'FOO\.bar') + self.assertEqual(t, 'FOO\.bar') + + def testToText9(self): + n = dns.name.from_text('FOO bar', origin=None) + t = n.to_unicode() + self.assertEqual(t, 'FOO\\032bar') + + def testToText10(self): + t = dns.name.empty.to_unicode() + self.assertEqual(t, '@') + + def testToText11(self): + t = dns.name.root.to_unicode() + self.assertEqual(t, '.') def testSlice1(self): n = dns.name.from_text(r'a.b.c.', origin=None) @@ -254,12 +272,12 @@ def testEmptyLabel1(self): def bad(): - n = dns.name.Name(['a', '', 'b']) + dns.name.Name(['a', '', 'b']) self.failUnlessRaises(dns.name.EmptyLabel, bad) def testEmptyLabel2(self): def bad(): - n = dns.name.Name(['', 'b']) + dns.name.Name(['', 'b']) self.failUnlessRaises(dns.name.EmptyLabel, bad) def testEmptyLabel3(self): @@ -272,7 +290,7 @@ def testLabelTooLong(self): def bad(): - n = dns.name.Name(['a' * 64, 'b']) + dns.name.Name(['a' * 64, 'b']) self.failUnlessRaises(dns.name.LabelTooLong, bad) def testLongName(self): @@ -281,7 +299,7 @@ def testNameTooLong(self): def bad(): - n = dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 63]) + dns.name.Name(['a' * 63, 'a' * 63, 'a' * 63, 'a' * 63]) self.failUnlessRaises(dns.name.NameTooLong, bad) def testConcat1(self): @@ -298,32 +316,32 @@ r = n1 + n2 self.failUnless(r == e) - def testConcat2(self): + def testConcat3(self): n1 = dns.name.Name([]) n2 = dns.name.Name(['a', 'b']) e = dns.name.Name(['a', 'b']) r = n1 + n2 self.failUnless(r == e) - def testConcat3(self): + def testConcat4(self): n1 = dns.name.Name(['a', 'b', '']) n2 = dns.name.Name([]) e = dns.name.Name(['a', 'b', '']) r = n1 + n2 self.failUnless(r == e) - def testConcat4(self): + def testConcat5(self): n1 = dns.name.Name(['a', 'b']) n2 = dns.name.Name(['c', '']) e = dns.name.Name(['a', 'b', 'c', '']) r = n1 + n2 self.failUnless(r == e) - def testConcat5(self): + def testConcat6(self): def bad(): n1 = dns.name.Name(['a', 'b', '']) n2 = dns.name.Name(['c']) - r = n1 + n2 + return n1 + n2 self.failUnlessRaises(dns.name.AbsoluteConcatenation, bad) def testBadEscape(self): @@ -356,7 +374,7 @@ def testBadDigestable(self): def bad(): n = dns.name.from_text('FOO.bar', None) - d = n.to_digestable() + n.to_digestable() self.failUnlessRaises(dns.name.NeedAbsoluteNameOrOrigin, bad) def testToWire1(self): @@ -446,13 +464,13 @@ def testBadSplit1(self): def bad(): n = dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(-1) + n.split(-1) self.failUnlessRaises(ValueError, bad) def testBadSplit2(self): def bad(): n = dns.name.from_text('foo.bar.') - (prefix, suffix) = n.split(4) + n.split(4) self.failUnlessRaises(ValueError, bad) def testRelativize1(self): @@ -540,7 +558,7 @@ self.failUnless(n.choose_relativity(o, False) == e) def testFromWire1(self): - w = '\x03foo\x00\xc0\x00' + w = b'\x03foo\x00\xc0\x00' (n1, cused1) = dns.name.from_wire(w, 0) (n2, cused2) = dns.name.from_wire(w, cused1) en1 = dns.name.from_text('foo.') @@ -550,7 +568,7 @@ self.failUnless(n1 == en1 and cused1 == ecused1 and \ n2 == en2 and cused2 == ecused2) - def testFromWire1(self): + def testFromWire2(self): w = b'\x03foo\x00\x01a\xc0\x00\x01b\xc0\x05' current = 0 (n1, cused1) = dns.name.from_wire(w, current) @@ -571,25 +589,25 @@ def testBadFromWire1(self): def bad(): w = b'\x03foo\xc0\x04' - (n, cused) = dns.name.from_wire(w, 0) + dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadPointer, bad) def testBadFromWire2(self): def bad(): w = b'\x03foo\xc0\x05' - (n, cused) = dns.name.from_wire(w, 0) + dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadPointer, bad) def testBadFromWire3(self): def bad(): w = b'\xbffoo' - (n, cused) = dns.name.from_wire(w, 0) + dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadLabelType, bad) def testBadFromWire4(self): def bad(): w = b'\x41foo' - (n, cused) = dns.name.from_wire(w, 0) + dns.name.from_wire(w, 0) self.failUnlessRaises(dns.name.BadLabelType, bad) def testParent1(self): @@ -634,6 +652,53 @@ n = dns.name.from_text(u'foo\uff61bar') self.assertEqual(n.labels, (b'foo', b'bar', b'')) + def testFromUnicodeIDNA2003Explicit(self): + t = u'Königsgäßchen' + e = dns.name.from_unicode(t, idna_codec=dns.name.IDNA_2003) + self.assertEqual(str(e), 'xn--knigsgsschen-lcb0w.') + + def testFromUnicodeIDNA2003Default(self): + t = u'Königsgäßchen' + e = dns.name.from_unicode(t) + self.assertEqual(str(e), 'xn--knigsgsschen-lcb0w.') + + def testFromUnicodeIDNA2008(self): + if dns.name.have_idna_2008: + t = u'Königsgäßchen' + def bad(): + codec = dns.name.IDNA_2008_Strict + return dns.name.from_unicode(t, idna_codec=codec) + self.failUnlessRaises(dns.name.IDNAException, bad) + e1 = dns.name.from_unicode(t, idna_codec=dns.name.IDNA_2008) + self.assertEqual(str(e1), 'xn--knigsgchen-b4a3dun.') + c2 = dns.name.IDNA_2008_Transitional + e2 = dns.name.from_unicode(t, idna_codec=c2) + self.assertEqual(str(e2), 'xn--knigsgsschen-lcb0w.') + + def testFromUnicodeIDNA2008Mixed(self): + # the IDN rules for names are very restrictive, disallowing + # practical names like u'_sip._tcp.Königsgäßchen'. Dnspython + # has a "practical" mode which permits labels which are purely + # ASCII to go straight through, and thus not invalid useful + # things in the real world. + if dns.name.have_idna_2008: + t = u'_sip._tcp.Königsgäßchen' + def bad1(): + codec = dns.name.IDNA_2008_Strict + return dns.name.from_unicode(t, idna_codec=codec) + def bad2(): + codec = dns.name.IDNA_2008_UTS_46 + return dns.name.from_unicode(t, idna_codec=codec) + def bad3(): + codec = dns.name.IDNA_2008_Transitional + return dns.name.from_unicode(t, idna_codec=codec) + self.failUnlessRaises(dns.name.IDNAException, bad1) + self.failUnlessRaises(dns.name.IDNAException, bad2) + self.failUnlessRaises(dns.name.IDNAException, bad3) + e = dns.name.from_unicode(t, + idna_codec=dns.name.IDNA_2008_Practical) + self.assertEqual(str(e), '_sip._tcp.xn--knigsgchen-b4a3dun.') + def testToUnicode1(self): n = dns.name.from_text(u'foo.bar') s = n.to_unicode() @@ -649,6 +714,29 @@ s = n.to_unicode() self.assertEqual(s, u'foo.bar.') + def testToUnicode4(self): + if dns.name.have_idna_2008: + n = dns.name.from_text(u'ドメイン.テスト', + idna_codec=dns.name.IDNA_2008) + s = n.to_unicode() + self.assertEqual(str(n), 'xn--eckwd4c7c.xn--zckzah.') + self.assertEqual(s, u'ドメイン.テスト.') + + def testDefaultDecodeIsJustPunycode(self): + # groß.com. in IDNA2008 form, pre-encoded. + n = dns.name.from_text('xn--gro-7ka.com') + # output using default codec which just decodes the punycode and + # doesn't test for IDNA2003 or IDNA2008. + self.assertEqual(n.to_unicode(), u'groß.com.') + + def testStrictINDA2003Decode(self): + # groß.com. in IDNA2008 form, pre-encoded. + n = dns.name.from_text('xn--gro-7ka.com') + def bad(): + # This throws in IDNA2003 because it doesn't "round trip". + n.to_unicode(idna_codec=dns.name.IDNA_2003_Strict) + self.failUnlessRaises(dns.name.IDNAException, bad) + def testReverseIPv4(self): e = dns.name.from_text('1.0.0.127.in-addr.arpa.') n = dns.reversename.from_address('127.0.0.1') @@ -666,12 +754,12 @@ def testBadReverseIPv4(self): def bad(): - n = dns.reversename.from_address('127.0.foo.1') + dns.reversename.from_address('127.0.foo.1') self.failUnlessRaises(dns.exception.SyntaxError, bad) def testBadReverseIPv6(self): def bad(): - n = dns.reversename.from_address('::1::1') + dns.reversename.from_address('::1::1') self.failUnlessRaises(dns.exception.SyntaxError, bad) def testForwardIPv4(self): @@ -682,7 +770,7 @@ def testForwardIPv6(self): n = dns.name.from_text('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.') - e = b'::1' + e = '::1' text = dns.reversename.to_address(n) self.assertEqual(text, e) @@ -696,7 +784,7 @@ n = dns.name.from_text('2.1.2.1.5.5.5.0.5.6.1.e164.arpa.') e = b'+16505551212' text = dns.e164.to_e164(n) - self.assertEqual(text,e) + self.assertEqual(text, e) if __name__ == '__main__': unittest.main() diff -Nru dnspython-1.14.0/tests/test_ntoaaton.py dnspython-1.15.0/tests/test_ntoaaton.py --- dnspython-1.14.0/tests/test_ntoaaton.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_ntoaaton.py 2016-09-20 16:24:02.000000000 +0000 @@ -13,6 +13,8 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +from __future__ import print_function + try: import unittest2 as unittest except ImportError: @@ -37,19 +39,19 @@ def test_aton1(self): a = aton6('::') - self.failUnless(a == '\x00' * 16) + self.failUnless(a == b'\x00' * 16) def test_aton2(self): a = aton6('::1') - self.failUnless(a == '\x00' * 15 + '\x01') + self.failUnless(a == b'\x00' * 15 + b'\x01') def test_aton3(self): a = aton6('::10.0.0.1') - self.failUnless(a == '\x00' * 12 + '\x0a\x00\x00\x01') + self.failUnless(a == b'\x00' * 12 + b'\x0a\x00\x00\x01') def test_aton4(self): a = aton6('abcd::dcba') - self.failUnless(a == '\xab\xcd' + '\x00' * 12 + '\xdc\xba') + self.failUnless(a == b'\xab\xcd' + b'\x00' * 12 + b'\xdc\xba') def test_aton5(self): a = aton6('1:2:3:4:5:6:7:8') @@ -58,113 +60,113 @@ def test_bad_aton1(self): def bad(): - a = aton6('abcd:dcba') + aton6('abcd:dcba') self.failUnlessRaises(dns.exception.SyntaxError, bad) def test_bad_aton2(self): def bad(): - a = aton6('abcd::dcba::1') + aton6('abcd::dcba::1') self.failUnlessRaises(dns.exception.SyntaxError, bad) def test_bad_aton3(self): def bad(): - a = aton6('1:2:3:4:5:6:7:8:9') + aton6('1:2:3:4:5:6:7:8:9') self.failUnlessRaises(dns.exception.SyntaxError, bad) - def test_aton1(self): + def test_aton6(self): a = aton6('::') self.assertEqual(a, b'\x00' * 16) - def test_aton2(self): + def test_aton7(self): a = aton6('::1') self.assertEqual(a, b'\x00' * 15 + b'\x01') - def test_aton3(self): + def test_aton8(self): a = aton6('::10.0.0.1') self.assertEqual(a, b'\x00' * 12 + b'\x0a\x00\x00\x01') - def test_aton4(self): + def test_aton9(self): a = aton6('abcd::dcba') self.assertEqual(a, b'\xab\xcd' + b'\x00' * 12 + b'\xdc\xba') def test_ntoa1(self): b = binascii.unhexlify(b'00010002000300040005000600070008') t = ntoa6(b) - self.assertEqual(t, b'1:2:3:4:5:6:7:8') + self.assertEqual(t, '1:2:3:4:5:6:7:8') def test_ntoa2(self): b = b'\x00' * 16 t = ntoa6(b) - self.assertEqual(t, b'::') + self.assertEqual(t, '::') def test_ntoa3(self): b = b'\x00' * 15 + b'\x01' t = ntoa6(b) - self.assertEqual(t, b'::1') + self.assertEqual(t, '::1') def test_ntoa4(self): b = b'\x80' + b'\x00' * 15 t = ntoa6(b) - self.assertEqual(t, b'8000::') + self.assertEqual(t, '8000::') def test_ntoa5(self): b = b'\x01\xcd' + b'\x00' * 12 + b'\x03\xef' t = ntoa6(b) - self.assertEqual(t, b'1cd::3ef') + self.assertEqual(t, '1cd::3ef') def test_ntoa6(self): b = binascii.unhexlify(b'ffff00000000ffff000000000000ffff') t = ntoa6(b) - self.assertEqual(t, b'ffff:0:0:ffff::ffff') + self.assertEqual(t, 'ffff:0:0:ffff::ffff') def test_ntoa7(self): b = binascii.unhexlify(b'00000000ffff000000000000ffffffff') t = ntoa6(b) - self.assertEqual(t, b'0:0:ffff::ffff:ffff') + self.assertEqual(t, '0:0:ffff::ffff:ffff') def test_ntoa8(self): b = binascii.unhexlify(b'ffff0000ffff00000000ffff00000000') t = ntoa6(b) - self.assertEqual(t, b'ffff:0:ffff::ffff:0:0') + self.assertEqual(t, 'ffff:0:ffff::ffff:0:0') def test_ntoa9(self): b = binascii.unhexlify(b'0000000000000000000000000a000001') t = ntoa6(b) - self.assertEqual(t, b'::10.0.0.1') + self.assertEqual(t, '::10.0.0.1') def test_ntoa10(self): b = binascii.unhexlify(b'0000000000000000000000010a000001') t = ntoa6(b) - self.assertEqual(t, b'::1:a00:1') + self.assertEqual(t, '::1:a00:1') def test_ntoa11(self): b = binascii.unhexlify(b'00000000000000000000ffff0a000001') t = ntoa6(b) - self.assertEqual(t, b'::ffff:10.0.0.1') + self.assertEqual(t, '::ffff:10.0.0.1') def test_ntoa12(self): b = binascii.unhexlify(b'000000000000000000000000ffffffff') t = ntoa6(b) - self.assertEqual(t, b'::255.255.255.255') + self.assertEqual(t, '::255.255.255.255') def test_ntoa13(self): b = binascii.unhexlify(b'00000000000000000000ffffffffffff') t = ntoa6(b) - self.assertEqual(t, b'::ffff:255.255.255.255') + self.assertEqual(t, '::ffff:255.255.255.255') def test_ntoa14(self): b = binascii.unhexlify(b'0000000000000000000000000001ffff') t = ntoa6(b) - self.assertEqual(t, b'::0.1.255.255') + self.assertEqual(t, '::0.1.255.255') def test_bad_ntoa1(self): def bad(): - a = ntoa6('') + ntoa6('') self.failUnlessRaises(ValueError, bad) def test_bad_ntoa2(self): def bad(): - a = ntoa6('\x00' * 17) + ntoa6('\x00' * 17) self.failUnlessRaises(ValueError, bad) def test_good_v4_aton(self): @@ -199,7 +201,7 @@ self.failUnlessRaises(dns.exception.SyntaxError, make_bad(addr)) def test_rfc5952_section_4_2_2(self): - addr = b'2001:db8:0:1:1:1:1:1' + addr = '2001:db8:0:1:1:1:1:1' b1 = aton6(addr) t1 = ntoa6(b1) self.assertEqual(t1, addr) diff -Nru dnspython-1.14.0/tests/test_rdtypeandclass.py dnspython-1.15.0/tests/test_rdtypeandclass.py --- dnspython-1.14.0/tests/test_rdtypeandclass.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_rdtypeandclass.py 2016-09-20 16:24:02.000000000 +0000 @@ -24,7 +24,7 @@ class RdTypeAndClassTestCase(unittest.TestCase): # Classes - + def test_class_meta1(self): self.failUnless(dns.rdataclass.is_metaclass(dns.rdataclass.ANY)) @@ -44,32 +44,32 @@ def test_class_bytext_bounds2(self): def bad(): - junk = dns.rdataclass.from_text('CLASS65536') + dns.rdataclass.from_text('CLASS65536') self.failUnlessRaises(ValueError, bad) def test_class_bytext_unknown(self): def bad(): - junk = dns.rdataclass.from_text('XXX') + dns.rdataclass.from_text('XXX') self.failUnlessRaises(dns.rdataclass.UnknownRdataclass, bad) def test_class_totext1(self): self.failUnless(dns.rdataclass.to_text(dns.rdataclass.IN) == 'IN') - def test_class_totext1(self): + def test_class_totext2(self): self.failUnless(dns.rdataclass.to_text(999) == 'CLASS999') def test_class_totext_bounds1(self): def bad(): - junk = dns.rdataclass.to_text(-1) + dns.rdataclass.to_text(-1) self.failUnlessRaises(ValueError, bad) def test_class_totext_bounds2(self): def bad(): - junk = dns.rdataclass.to_text(65536) + dns.rdataclass.to_text(65536) self.failUnlessRaises(ValueError, bad) # Types - + def test_type_meta1(self): self.failUnless(dns.rdatatype.is_metatype(dns.rdatatype.ANY)) @@ -98,28 +98,28 @@ def test_type_bytext_bounds2(self): def bad(): - junk = dns.rdatatype.from_text('TYPE65536') + dns.rdatatype.from_text('TYPE65536') self.failUnlessRaises(ValueError, bad) def test_type_bytext_unknown(self): def bad(): - junk = dns.rdatatype.from_text('XXX') + dns.rdatatype.from_text('XXX') self.failUnlessRaises(dns.rdatatype.UnknownRdatatype, bad) def test_type_totext1(self): self.failUnless(dns.rdatatype.to_text(dns.rdatatype.A) == 'A') - def test_type_totext1(self): + def test_type_totext2(self): self.failUnless(dns.rdatatype.to_text(999) == 'TYPE999') def test_type_totext_bounds1(self): def bad(): - junk = dns.rdatatype.to_text(-1) + dns.rdatatype.to_text(-1) self.failUnlessRaises(ValueError, bad) def test_type_totext_bounds2(self): def bad(): - junk = dns.rdatatype.to_text(65536) + dns.rdatatype.to_text(65536) self.failUnlessRaises(ValueError, bad) if __name__ == '__main__': diff -Nru dnspython-1.14.0/tests/test_rdtypeanyeui.py dnspython-1.15.0/tests/test_rdtypeanyeui.py --- dnspython-1.14.0/tests/test_rdtypeanyeui.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_rdtypeanyeui.py 2016-09-20 16:24:02.000000000 +0000 @@ -18,7 +18,7 @@ import unittest2 as unittest except ImportError: import unittest -from io import BytesIO, StringIO +from io import BytesIO import dns.rrset import dns.rdtypes.ANY.EUI48 diff -Nru dnspython-1.14.0/tests/test_resolver.py dnspython-1.15.0/tests/test_resolver.py --- dnspython-1.14.0/tests/test_resolver.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_resolver.py 2016-09-20 16:24:02.000000000 +0000 @@ -16,13 +16,13 @@ from io import StringIO import select import sys +import socket import time try: import unittest2 as unittest except ImportError: import unittest -import dns.name import dns.message import dns.name import dns.rdataclass @@ -30,6 +30,14 @@ import dns.resolver from dns._compat import xrange +# Some tests require the internet to be available to run, so let's +# skip those if it's not there. +_network_available = True +try: + socket.gethostbyname('dnspython.org') +except socket.gaierror: + _network_available = False + resolv_conf = u""" /t/t # comment 1 @@ -51,11 +59,51 @@ ;ADDITIONAL """ +dangling_cname_0_message_text = """id 10000 +opcode QUERY +rcode NOERROR +flags QR AA RD RA +;QUESTION +91.11.17.172.in-addr.arpa.none. IN PTR +;ANSWER +;AUTHORITY +;ADDITIONAL +""" + +dangling_cname_1_message_text = """id 10001 +opcode QUERY +rcode NOERROR +flags QR AA RD RA +;QUESTION +91.11.17.172.in-addr.arpa. IN PTR +;ANSWER +11.17.172.in-addr.arpa. 86400 IN DNAME 11.8-22.17.172.in-addr.arpa. +91.11.17.172.in-addr.arpa. 86400 IN CNAME 91.11.8-22.17.172.in-addr.arpa. +;AUTHORITY +;ADDITIONAL +""" + +dangling_cname_2_message_text = """id 10002 +opcode QUERY +rcode NOERROR +flags QR AA RD RA +;QUESTION +91.11.17.172.in-addr.arpa.example. IN PTR +;ANSWER +91.11.17.172.in-addr.arpa.example. 86400 IN CNAME 91.11.17.172.in-addr.arpa.base. +91.11.17.172.in-addr.arpa.base. 86400 IN CNAME 91.11.17.172.clients.example. +91.11.17.172.clients.example. 86400 IN CNAME 91-11-17-172.dynamic.example. +;AUTHORITY +;ADDITIONAL +""" + + class FakeAnswer(object): def __init__(self, expiration): self.expiration = expiration -class BaseResolverTests(object): + +class BaseResolverTests(unittest.TestCase): if sys.platform != 'win32': def testRead(self): @@ -86,18 +134,21 @@ self.failUnless(cache.get((name, dns.rdatatype.A, dns.rdataclass.IN)) is None) + @unittest.skipIf(not _network_available, "Internet not reachable") def testZoneForName1(self): name = dns.name.from_text('www.dnspython.org.') ezname = dns.name.from_text('dnspython.org.') zname = dns.resolver.zone_for_name(name) self.failUnless(zname == ezname) + @unittest.skipIf(not _network_available, "Internet not reachable") def testZoneForName2(self): name = dns.name.from_text('a.b.www.dnspython.org.') ezname = dns.name.from_text('dnspython.org.') zname = dns.resolver.zone_for_name(name) self.failUnless(zname == ezname) + @unittest.skipIf(not _network_available, "Internet not reachable") def testZoneForName3(self): name = dns.name.from_text('dnspython.org.') ezname = dns.name.from_text('dnspython.org.') @@ -107,7 +158,7 @@ def testZoneForName4(self): def bad(): name = dns.name.from_text('dnspython.org', None) - zname = dns.resolver.zone_for_name(name) + dns.resolver.zone_for_name(name) self.failUnlessRaises(dns.resolver.NotAbsolute, bad) def testLRUReplace(self): @@ -163,6 +214,23 @@ dns.rdataclass.IN)) is None) + def testEmptyAnswerSection(self): + # TODO: dangling_cname_0_message_text was the only sample message + # with an empty answer section. Other than that it doesn't + # apply. + message = dns.message.from_text(dangling_cname_0_message_text) + name = dns.name.from_text('example.') + answer = dns.resolver.Answer(name, dns.rdatatype.A, dns.rdataclass.IN, + message, raise_on_no_answer=False) + def test_python_internal_truth(answer): + if answer: + return True + else: + return False + self.assertFalse(test_python_internal_truth(answer)) + for a in answer: + pass + class PollingMonkeyPatchMixin(object): def setUp(self): self.__native_polling_backend = dns.query._polling_backend @@ -184,5 +252,152 @@ def polling_backend(self): return dns.query._poll_for + +class NXDOMAINExceptionTestCase(unittest.TestCase): + + # pylint: disable=broad-except + + def test_nxdomain_compatible(self): + n1 = dns.name.Name(('a', 'b', '')) + n2 = dns.name.Name(('a', 'b', 's', '')) + py3 = (sys.version_info[0] > 2) + + try: + raise dns.resolver.NXDOMAIN + except dns.exception.DNSException as e: + if not py3: + self.assertTrue((e.message == e.__doc__)) + self.assertTrue((e.args == (e.__doc__,))) + self.assertTrue(('kwargs' in dir(e))) + self.assertTrue((str(e) == e.__doc__), str(e)) + self.assertTrue(('qnames' not in e.kwargs)) + self.assertTrue(('responses' not in e.kwargs)) + + try: + raise dns.resolver.NXDOMAIN("errmsg") + except dns.exception.DNSException as e: + if not py3: + self.assertTrue((e.message == "errmsg")) + self.assertTrue((e.args == ("errmsg",))) + self.assertTrue(('kwargs' in dir(e))) + self.assertTrue((str(e) == "errmsg"), str(e)) + self.assertTrue(('qnames' not in e.kwargs)) + self.assertTrue(('responses' not in e.kwargs)) + + try: + raise dns.resolver.NXDOMAIN("errmsg", -1) + except dns.exception.DNSException as e: + if not py3: + self.assertTrue((e.message == "")) + self.assertTrue((e.args == ("errmsg", -1))) + self.assertTrue(('kwargs' in dir(e))) + self.assertTrue((str(e) == "('errmsg', -1)"), str(e)) + self.assertTrue(('qnames' not in e.kwargs)) + self.assertTrue(('responses' not in e.kwargs)) + + try: + raise dns.resolver.NXDOMAIN(qnames=None) + except Exception as e: + self.assertTrue((isinstance(e, AttributeError))) + + try: + raise dns.resolver.NXDOMAIN(qnames=n1) + except Exception as e: + self.assertTrue((isinstance(e, AttributeError))) + + try: + raise dns.resolver.NXDOMAIN(qnames=[]) + except Exception as e: + self.assertTrue((isinstance(e, AttributeError))) + + try: + raise dns.resolver.NXDOMAIN(qnames=[n1]) + except dns.exception.DNSException as e: + MSG = "The DNS query name does not exist: a.b." + if not py3: + self.assertTrue((e.message == MSG), e.message) + self.assertTrue((e.args == (MSG,)), repr(e.args)) + self.assertTrue(('kwargs' in dir(e))) + self.assertTrue((str(e) == MSG), str(e)) + self.assertTrue(('qnames' in e.kwargs)) + self.assertTrue((e.kwargs['qnames'] == [n1])) + self.assertTrue(('responses' in e.kwargs)) + self.assertTrue((e.kwargs['responses'] == {})) + + try: + raise dns.resolver.NXDOMAIN(qnames=[n2, n1]) + except Exception as e: + e0 = dns.resolver.NXDOMAIN("errmsg") + e = e0 + e + MSG = "None of DNS query names exist: a.b.s., a.b." + if not py3: + self.assertTrue((e.message == MSG), e.message) + self.assertTrue((e.args == (MSG,)), repr(e.args)) + self.assertTrue(('kwargs' in dir(e))) + self.assertTrue((str(e) == MSG), str(e)) + self.assertTrue(('qnames' in e.kwargs)) + self.assertTrue((e.kwargs['qnames'] == [n2, n1])) + self.assertTrue(('responses' in e.kwargs)) + self.assertTrue((e.kwargs['responses'] == {})) + + try: + raise dns.resolver.NXDOMAIN(qnames=[n1], responses=['r1.1']) + except Exception as e: + self.assertTrue((isinstance(e, AttributeError))) + + try: + raise dns.resolver.NXDOMAIN(qnames=[n1], responses={n1: 'r1.1'}) + except Exception as e: + MSG = "The DNS query name does not exist: a.b." + if not py3: + self.assertTrue((e.message == MSG), e.message) + self.assertTrue((e.args == (MSG,)), repr(e.args)) + self.assertTrue(('kwargs' in dir(e))) + self.assertTrue((str(e) == MSG), str(e)) + self.assertTrue(('qnames' in e.kwargs)) + self.assertTrue((e.kwargs['qnames'] == [n1])) + self.assertTrue(('responses' in e.kwargs)) + self.assertTrue((e.kwargs['responses'] == {n1: 'r1.1'})) + + def test_nxdomain_merge(self): + n1 = dns.name.Name(('a', 'b', '')) + n2 = dns.name.Name(('a', 'b', '')) + n3 = dns.name.Name(('a', 'b', 'c', '')) + n4 = dns.name.Name(('a', 'b', 'd', '')) + responses1 = {n1: 'r1.1', n2: 'r1.2', n4: 'r1.4'} + qnames1 = [n1, n4] # n2 == n1 + responses2 = {n2: 'r2.2', n3: 'r2.3'} + qnames2 = [n2, n3] + e0 = dns.resolver.NXDOMAIN() + e1 = dns.resolver.NXDOMAIN(qnames=qnames1, responses=responses1) + e2 = dns.resolver.NXDOMAIN(qnames=qnames2, responses=responses2) + e = e1 + e0 + e2 + self.assertRaises(AttributeError, lambda: e0 + e0) + self.assertTrue(e.kwargs['qnames'] == [n1, n4, n3], repr(e.kwargs['qnames'])) + self.assertTrue(e.kwargs['responses'][n1].startswith('r2.')) + self.assertTrue(e.kwargs['responses'][n2].startswith('r2.')) + self.assertTrue(e.kwargs['responses'][n3].startswith('r2.')) + self.assertTrue(e.kwargs['responses'][n4].startswith('r1.')) + + def test_nxdomain_canonical_name(self): + cname1 = "91.11.8-22.17.172.in-addr.arpa." + cname2 = "91-11-17-172.dynamic.example." + message0 = dns.message.from_text(dangling_cname_0_message_text) + message1 = dns.message.from_text(dangling_cname_1_message_text) + message2 = dns.message.from_text(dangling_cname_2_message_text) + qname0 = message0.question[0].name + qname1 = message1.question[0].name + qname2 = message2.question[0].name + responses = {qname0: message0, qname1: message1, qname2: message2} + eX = dns.resolver.NXDOMAIN() + e0 = dns.resolver.NXDOMAIN(qnames=[qname0], responses=responses) + e1 = dns.resolver.NXDOMAIN(qnames=[qname0, qname1, qname2], responses=responses) + e2 = dns.resolver.NXDOMAIN(qnames=[qname0, qname2, qname1], responses=responses) + self.assertRaises(TypeError, lambda: eX.canonical_name) + self.assertTrue(e0.canonical_name == qname0) + self.assertTrue(e1.canonical_name == dns.name.from_text(cname1)) + self.assertTrue(e2.canonical_name == dns.name.from_text(cname2)) + + if __name__ == '__main__': unittest.main() diff -Nru dnspython-1.14.0/tests/test_rrset.py dnspython-1.15.0/tests/test_rrset.py --- dnspython-1.14.0/tests/test_rrset.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_rrset.py 2016-09-20 16:24:02.000000000 +0000 @@ -21,7 +21,7 @@ import dns.rrset class RRsetTestCase(unittest.TestCase): - + def testEqual1(self): r1 = dns.rrset.from_text('foo', 300, 'in', 'a', '10.0.0.1', '10.0.0.2') r2 = dns.rrset.from_text('FOO', 300, 'in', 'a', '10.0.0.2', '10.0.0.1') diff -Nru dnspython-1.14.0/tests/test_set.py dnspython-1.15.0/tests/test_set.py --- dnspython-1.14.0/tests/test_set.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_set.py 2016-09-20 16:24:02.000000000 +0000 @@ -24,7 +24,7 @@ S = dns.set.Set class SimpleSetTestCase(unittest.TestCase): - + def testLen1(self): s1 = S() self.failUnless(len(s1) == 0) diff -Nru dnspython-1.14.0/tests/test_tokenizer.py dnspython-1.15.0/tests/test_tokenizer.py --- dnspython-1.14.0/tests/test_tokenizer.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_tokenizer.py 2016-09-20 16:24:02.000000000 +0000 @@ -13,7 +13,6 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -import unittest try: import unittest2 as unittest except ImportError: @@ -59,19 +58,19 @@ def testQuotedString5(self): def bad(): tok = dns.tokenizer.Tokenizer(r'"foo') - token = tok.get() + tok.get() self.failUnlessRaises(dns.exception.UnexpectedEnd, bad) def testQuotedString6(self): def bad(): tok = dns.tokenizer.Tokenizer(r'"foo\01') - token = tok.get() + tok.get() self.failUnlessRaises(dns.exception.SyntaxError, bad) def testQuotedString7(self): def bad(): tok = dns.tokenizer.Tokenizer('"foo\nbar"') - token = tok.get() + tok.get() self.failUnlessRaises(dns.exception.SyntaxError, bad) def testEmpty1(self): @@ -108,14 +107,14 @@ def testComment2(self): tok = dns.tokenizer.Tokenizer(' ;foo\n') - token1 = tok.get(want_comment = True) + token1 = tok.get(want_comment=True) token2 = tok.get() self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo') and token2.is_eol()) def testComment3(self): tok = dns.tokenizer.Tokenizer(' ;foo bar\n') - token1 = tok.get(want_comment = True) + token1 = tok.get(want_comment=True) token2 = tok.get() self.failUnless(token1 == Token(dns.tokenizer.COMMENT, 'foo bar') and token2.is_eol()) @@ -135,13 +134,13 @@ def testMultiline3(self): def bad(): tok = dns.tokenizer.Tokenizer('foo)') - tokens = list(iter(tok)) + list(iter(tok)) self.failUnlessRaises(dns.exception.SyntaxError, bad) def testMultiline4(self): def bad(): tok = dns.tokenizer.Tokenizer('((foo)') - tokens = list(iter(tok)) + list(iter(tok)) self.failUnlessRaises(dns.exception.SyntaxError, bad) def testUnget1(self): diff -Nru dnspython-1.14.0/tests/test_update.py dnspython-1.15.0/tests/test_update.py --- dnspython-1.14.0/tests/test_update.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/test_update.py 2016-09-20 16:24:02.000000000 +0000 @@ -40,7 +40,7 @@ goodwire = binascii.unhexlify(goodhex.replace(' ', '').encode()) -update_text="""id 1 +update_text = """id 1 opcode UPDATE rcode NOERROR ;ZONE @@ -74,7 +74,7 @@ update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') update.add('bar', 300, 'a', '10.0.0.3') update.delete('bar', 'a', '10.0.0.4') - update.delete('blaz','a') + update.delete('blaz', 'a') update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) @@ -89,7 +89,7 @@ update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') update.add('bar', 300, dns.rdata.from_text(1, 1, '10.0.0.3')) update.delete('bar', 'a', '10.0.0.4') - update.delete('blaz','a') + update.delete('blaz', 'a') update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) @@ -104,7 +104,7 @@ update.replace('foo', 300, 'a', '10.0.0.1', '10.0.0.2') update.add('bar', dns.rdataset.from_text(1, 1, 300, '10.0.0.3')) update.delete('bar', 'a', '10.0.0.4') - update.delete('blaz','a') + update.delete('blaz', 'a') update.delete('blaz2') self.failUnless(update.to_wire() == goodwire) diff -Nru dnspython-1.14.0/tests/test_wiredata.py dnspython-1.15.0/tests/test_wiredata.py --- dnspython-1.14.0/tests/test_wiredata.py 1970-01-01 00:00:00.000000000 +0000 +++ dnspython-1.15.0/tests/test_wiredata.py 2016-09-20 16:24:02.000000000 +0000 @@ -0,0 +1,126 @@ +# Copyright (C) 2016 +# Author: Martin Basti +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from dns.exception import FormError +from dns.wiredata import WireData + + +class WireDataSlicingTestCase(unittest.TestCase): + + def testSliceAll(self): + """Get all data""" + inst = WireData(b'0123456789') + self.assertEqual(inst[:], WireData(b'0123456789')) + + def testSliceAllExplicitlyDefined(self): + """Get all data""" + inst = WireData(b'0123456789') + self.assertEqual(inst[0:10], WireData(b'0123456789')) + + def testSliceLowerHalf(self): + """Get lower half of data""" + inst = WireData(b'0123456789') + self.assertEqual(inst[:5], WireData(b'01234')) + + def testSliceLowerHalfWithNegativeIndex(self): + """Get lower half of data""" + inst = WireData(b'0123456789') + self.assertEqual(inst[:-5], WireData(b'01234')) + + def testSliceUpperHalf(self): + """Get upper half of data""" + inst = WireData(b'0123456789') + self.assertEqual(inst[5:], WireData(b'56789')) + + def testSliceMiddle(self): + """Get data from middle""" + inst = WireData(b'0123456789') + self.assertEqual(inst[3:6], WireData(b'345')) + + def testSliceMiddleWithNegativeIndex(self): + """Get data from middle""" + inst = WireData(b'0123456789') + self.assertEqual(inst[-6:-3], WireData(b'456')) + + def testSliceMiddleWithMixedIndex(self): + """Get data from middle""" + inst = WireData(b'0123456789') + self.assertEqual(inst[-8:3], WireData(b'2')) + self.assertEqual(inst[5:-3], WireData(b'56')) + + def testGetOne(self): + """Get data one by one item""" + data = b'0123456789' + inst = WireData(data) + for i, byte in enumerate(bytearray(data)): + self.assertEqual(inst[i], byte) + for i in range(-1, len(data) * -1, -1): + self.assertEqual(inst[i], bytearray(data)[i]) + + def testEmptySlice(self): + """Test empty slice""" + data = b'0123456789' + inst = WireData(data) + for i, byte in enumerate(data): + self.assertEqual(inst[i:i], b'') + for i in range(-1, len(data) * -1, -1): + self.assertEqual(inst[i:i], b'') + self.assertEqual(inst[-3:-6], b'') + + def testSliceStartOutOfLowerBorder(self): + """Get data from out of lower border""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[-11:] # pylint: disable=pointless-statement + + def testSliceStopOutOfLowerBorder(self): + """Get data from out of lower border""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[:-11] # pylint: disable=pointless-statement + + def testSliceBothOutOfLowerBorder(self): + """Get data from out of lower border""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[-12:-11] # pylint: disable=pointless-statement + + def testSliceStartOutOfUpperBorder(self): + """Get data from out of upper border""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[11:] # pylint: disable=pointless-statement + + def testSliceStopOutOfUpperBorder(self): + """Get data from out of upper border""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[:11] # pylint: disable=pointless-statement + + def testSliceBothOutOfUpperBorder(self): + """Get data from out of lower border""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[10:20] # pylint: disable=pointless-statement + + def testGetOneOutOfLowerBorder(self): + """Get item outside of range""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[-11] # pylint: disable=pointless-statement + + def testGetOneOutOfUpperBorder(self): + """Get item outside of range""" + inst = WireData(b'0123456789') + with self.assertRaises(FormError): + inst[10] # pylint: disable=pointless-statement diff -Nru dnspython-1.14.0/tests/test_zone.py dnspython-1.15.0/tests/test_zone.py --- dnspython-1.14.0/tests/test_zone.py 2016-05-27 16:13:01.000000000 +0000 +++ dnspython-1.15.0/tests/test_zone.py 2016-09-20 16:24:02.000000000 +0000 @@ -132,6 +132,59 @@ os.unlink(here('example2.out')) self.failUnless(ok) + def testToFileTextualStream(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + f = StringIO() + z.to_file(f) + out = f.getvalue() + f.close() + self.assertEqual(out, example_text_output) + + def testToFileBinaryStream(self): + z = dns.zone.from_text(example_text, 'example.', relativize=True) + f = BytesIO() + z.to_file(f) + out = f.getvalue() + f.close() + self.assertEqual(out, example_text_output.encode()) + + def testToFileTextual(self): + z = dns.zone.from_file(here('example'), 'example') + try: + f = open(here('example3-textual.out'), 'w') + z.to_file(f) + f.close() + ok = filecmp.cmp(here('example3-textual.out'), + here('example3.good')) + finally: + if not _keep_output: + os.unlink(here('example3-textual.out')) + self.failUnless(ok) + + def testToFileBinary(self): + z = dns.zone.from_file(here('example'), 'example') + try: + f = open(here('example3-binary.out'), 'wb') + z.to_file(f) + f.close() + ok = filecmp.cmp(here('example3-binary.out'), + here('example3.good')) + finally: + if not _keep_output: + os.unlink(here('example3-binary.out')) + self.failUnless(ok) + + def testToFileFilename(self): + z = dns.zone.from_file(here('example'), 'example') + try: + z.to_file('example3-filename.out') + ok = filecmp.cmp(here('example3-filename.out'), + here('example3.good')) + finally: + if not _keep_output: + os.unlink(here('example3-filename.out')) + self.failUnless(ok) + def testToText(self): z = dns.zone.from_file(here('example'), 'example') ok = False @@ -166,7 +219,7 @@ f = BytesIO() o = dns.name.from_text('example.') z = dns.zone.from_file(here('example'), o) - for (name, node) in z.items(): + for node in z.values(): for rds in node: for rd in rds: f.seek(0) @@ -175,7 +228,7 @@ wire = f.getvalue() rd2 = dns.rdata.from_wire(rds.rdclass, rds.rdtype, wire, 0, len(wire), - origin = o) + origin=o) self.failUnless(rd == rd2) def testEqual(self): @@ -211,7 +264,7 @@ def testFindRdataset2(self): def bad(): z = dns.zone.from_text(example_text, 'example.', relativize=True) - rds = z.find_rdataset('@', 'loc') + z.find_rdataset('@', 'loc') self.failUnlessRaises(KeyError, bad) def testFindRRset1(self): @@ -223,7 +276,7 @@ def testFindRRset2(self): def bad(): z = dns.zone.from_text(example_text, 'example.', relativize=True) - rrs = z.find_rrset('@', 'loc') + z.find_rrset('@', 'loc') self.failUnlessRaises(KeyError, bad) def testGetRdataset1(self): @@ -235,7 +288,7 @@ def testGetRdataset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rds = z.get_rdataset('@', 'loc') - self.failUnless(rds == None) + self.failUnless(rds is None) def testGetRRset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) @@ -246,7 +299,7 @@ def testGetRRset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) rrs = z.get_rrset('@', 'loc') - self.failUnless(rrs == None) + self.failUnless(rrs is None) def testReplaceRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) @@ -285,7 +338,7 @@ def bad(): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] - rds = node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + node.find_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) self.failUnlessRaises(KeyError, bad) def testNodeGetRdataset1(self): @@ -299,21 +352,21 @@ z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) - self.failUnless(rds == None) + self.failUnless(rds is None) def testNodeDeleteRdataset1(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] - rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) + node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) - self.failUnless(rds == None) + self.failUnless(rds is None) def testNodeDeleteRdataset2(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) node = z['@'] - rds = node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) + node.delete_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) rds = node.get_rdataset(dns.rdataclass.IN, dns.rdatatype.LOC) - self.failUnless(rds == None) + self.failUnless(rds is None) def testIterateRdatasets(self): z = dns.zone.from_text(example_text, 'example.', relativize=True) @@ -391,14 +444,12 @@ def testNoSOA(self): def bad(): - z = dns.zone.from_text(no_soa_text, 'example.', - relativize=True) + dns.zone.from_text(no_soa_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoSOA, bad) def testNoNS(self): def bad(): - z = dns.zone.from_text(no_ns_text, 'example.', - relativize=True) + dns.zone.from_text(no_ns_text, 'example.', relativize=True) self.failUnlessRaises(dns.zone.NoNS, bad) def testInclude(self): @@ -409,8 +460,7 @@ def testBadDirective(self): def bad(): - z = dns.zone.from_text(bad_directive_text, 'example.', - relativize=True) + dns.zone.from_text(bad_directive_text, 'example.', relativize=True) self.failUnlessRaises(dns.exception.SyntaxError, bad) def testFirstRRStartsWithWhitespace(self): @@ -427,14 +477,14 @@ self.failUnless(z.origin == dns.name.from_text('example.')) def bad1(): o = dns.name.from_text('example', None) - z = dns.zone.Zone(o) + dns.zone.Zone(o) self.failUnlessRaises(ValueError, bad1) def bad2(): - z = dns.zone.Zone(1.0) + dns.zone.Zone(1.0) self.failUnlessRaises(ValueError, bad2) def testZoneOriginNone(self): - z = dns.zone.Zone(None) + dns.zone.Zone(None) if __name__ == '__main__': unittest.main() diff -Nru dnspython-1.14.0/tests/utest.py dnspython-1.15.0/tests/utest.py --- dnspython-1.14.0/tests/utest.py 2016-05-17 14:22:28.000000000 +0000 +++ dnspython-1.15.0/tests/utest.py 2016-09-20 16:24:02.000000000 +0000 @@ -8,5 +8,5 @@ if __name__ == '__main__': sys.path.insert(0, os.path.realpath('..')) suites = unittest.defaultTestLoader.discover('.') - if (not unittest.TextTestRunner(verbosity=2).run(suites).wasSuccessful()): + if not unittest.TextTestRunner(verbosity=2).run(suites).wasSuccessful(): sys.exit(1)