diff options
-rw-r--r-- | .flake8 | 2 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | dns/_asyncio_backend.py | 4 | ||||
-rw-r--r-- | dns/_curio_backend.py | 2 | ||||
-rw-r--r-- | dns/_trio_backend.py | 2 | ||||
-rw-r--r-- | dns/asyncbackend.py | 5 | ||||
-rw-r--r-- | dns/asyncresolver.py | 8 | ||||
-rw-r--r-- | dns/dnssec.py | 27 | ||||
-rw-r--r-- | dns/edns.py | 16 | ||||
-rw-r--r-- | dns/flags.py | 23 | ||||
-rw-r--r-- | dns/ipv6.py | 2 | ||||
-rw-r--r-- | dns/message.py | 20 | ||||
-rw-r--r-- | dns/name.py | 4 | ||||
-rw-r--r-- | dns/opcode.py | 12 | ||||
-rw-r--r-- | dns/query.py | 34 | ||||
-rw-r--r-- | dns/rcode.py | 27 | ||||
-rw-r--r-- | dns/rdataclass.py | 15 | ||||
-rw-r--r-- | dns/rdataset.py | 2 | ||||
-rw-r--r-- | dns/rdatatype.py | 80 | ||||
-rw-r--r-- | dns/rdtypes/CH/A.py | 3 | ||||
-rw-r--r-- | dns/rdtypes/dnskeybase.py | 10 | ||||
-rw-r--r-- | dns/resolver.py | 35 | ||||
-rw-r--r-- | dns/rrset.py | 20 | ||||
-rw-r--r-- | dns/update.py | 11 | ||||
-rw-r--r-- | dns/zone.py | 6 | ||||
-rw-r--r-- | pylintrc | 23 | ||||
-rw-r--r-- | tests/test_constants.py | 38 | ||||
-rw-r--r-- | tests/util.py | 19 | ||||
-rwxr-xr-x | util/constants-tool | 85 |
29 files changed, 453 insertions, 85 deletions
@@ -6,6 +6,8 @@ ignore = E129, # Whitespace round parameter '=' can be excessive E252, + # Multiple # in a comment is OK + E266, # Not excited by the "two blank lines" rule E302, E305, @@ -58,6 +58,9 @@ potestlf: potype: poetry run python -m mypy examples tests dns/*.py +polint: + poetry run pylint dns/*.py + poflake: poetry run flake8 dns diff --git a/dns/_asyncio_backend.py b/dns/_asyncio_backend.py index 3af34ff..1cf1519 100644 --- a/dns/_asyncio_backend.py +++ b/dns/_asyncio_backend.py @@ -86,14 +86,12 @@ class StreamSocket(dns._asyncbackend.DatagramSocket): self.writer = writer async def sendall(self, what, timeout): - self.writer.write(what), + self.writer.write(what) return await _maybe_wait_for(self.writer.drain(), timeout) - raise dns.exception.Timeout(timeout=timeout) async def recv(self, count, timeout): return await _maybe_wait_for(self.reader.read(count), timeout) - raise dns.exception.Timeout(timeout=timeout) async def close(self): self.writer.close() diff --git a/dns/_curio_backend.py b/dns/_curio_backend.py index 300e1b8..894e87c 100644 --- a/dns/_curio_backend.py +++ b/dns/_curio_backend.py @@ -21,6 +21,8 @@ def _maybe_timeout(timeout): # for brevity _lltuple = dns.inet.low_level_address_tuple +# pylint: disable=redefined-outer-name + class DatagramSocket(dns._asyncbackend.DatagramSocket): def __init__(self, socket): diff --git a/dns/_trio_backend.py b/dns/_trio_backend.py index 92ea879..82512cd 100644 --- a/dns/_trio_backend.py +++ b/dns/_trio_backend.py @@ -21,6 +21,8 @@ def _maybe_timeout(timeout): # for brevity _lltuple = dns.inet.low_level_address_tuple +# pylint: disable=redefined-outer-name + class DatagramSocket(dns._asyncbackend.DatagramSocket): def __init__(self, socket): diff --git a/dns/asyncbackend.py b/dns/asyncbackend.py index 9582a6f..e6a42ce 100644 --- a/dns/asyncbackend.py +++ b/dns/asyncbackend.py @@ -2,9 +2,12 @@ import dns.exception +# pylint: disable=unused-import + from dns._asyncbackend import Socket, DatagramSocket, \ StreamSocket, Backend # noqa: +# pylint: enable=unused-import _default_backend = None @@ -25,6 +28,7 @@ def get_backend(name): Raises NotImplementError if an unknown backend name is specified. """ + # pylint: disable=import-outside-toplevel,redefined-outer-name backend = _backends.get(name) if backend: return backend @@ -50,6 +54,7 @@ def sniff(): Returns the name of the library, or raises AsyncLibraryNotFoundError if the library cannot be determined. """ + # pylint: disable=import-outside-toplevel try: if _no_sniffio: raise ImportError diff --git a/dns/asyncresolver.py b/dns/asyncresolver.py index b0af934..a6582b2 100644 --- a/dns/asyncresolver.py +++ b/dns/asyncresolver.py @@ -36,6 +36,8 @@ _tcp = dns.asyncquery.tcp class Resolver(dns.resolver.Resolver): + # pylint: disable=invalid-overridden-method, arguments-differ + async def resolve(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, tcp=False, source=None, raise_on_no_answer=True, @@ -139,11 +141,15 @@ class Resolver(dns.resolver.Resolver): if answer is not None: return answer + # pylint: disable=signature-differs + async def query(self, *args, **kwargs): # We have to define something here as we don't want to inherit the # parent's query(). raise NotImplementedError + # pylint: enable=signature-differs + async def resolve_address(self, ipaddr, *args, **kwargs): """Use an asynchronous resolver to run a reverse query for PTR records. @@ -165,6 +171,8 @@ class Resolver(dns.resolver.Resolver): rdclass=dns.rdataclass.IN, *args, **kwargs) + # pylint: disable=redefined-outer-name + async def canonical_name(self, name): """Determine the canonical name of *name*. diff --git a/dns/dnssec.py b/dns/dnssec.py index e36e729..095fabd 100644 --- a/dns/dnssec.py +++ b/dns/dnssec.py @@ -64,9 +64,6 @@ class Algorithm(dns.enum.IntEnum): return 255 -globals().update(Algorithm.__members__) - - def algorithm_from_text(text): """Convert text into a DNSSEC algorithm value. @@ -551,7 +548,7 @@ def nsec3_hash(domain, salt, iterations, algorithm): domain_encoded = domain.canonicalize().to_wire() digest = hashlib.sha1(domain_encoded + salt_encoded).digest() - for i in range(iterations): + for _ in range(iterations): digest = hashlib.sha1(digest + salt_encoded).digest() output = base64.b32encode(digest).decode("utf-8") @@ -584,3 +581,25 @@ else: validate = _validate # type: ignore validate_rrsig = _validate_rrsig # type: ignore _have_pyca = True + +### BEGIN generated Algorithm constants + +RSAMD5 = Algorithm.RSAMD5 +DH = Algorithm.DH +DSA = Algorithm.DSA +ECC = Algorithm.ECC +RSASHA1 = Algorithm.RSASHA1 +DSANSEC3SHA1 = Algorithm.DSANSEC3SHA1 +RSASHA1NSEC3SHA1 = Algorithm.RSASHA1NSEC3SHA1 +RSASHA256 = Algorithm.RSASHA256 +RSASHA512 = Algorithm.RSASHA512 +ECCGOST = Algorithm.ECCGOST +ECDSAP256SHA256 = Algorithm.ECDSAP256SHA256 +ECDSAP384SHA384 = Algorithm.ECDSAP384SHA384 +ED25519 = Algorithm.ED25519 +ED448 = Algorithm.ED448 +INDIRECT = Algorithm.INDIRECT +PRIVATEDNS = Algorithm.PRIVATEDNS +PRIVATEOID = Algorithm.PRIVATEOID + +### END generated Algorithm constants diff --git a/dns/edns.py b/dns/edns.py index 087592b..199e8c4 100644 --- a/dns/edns.py +++ b/dns/edns.py @@ -50,7 +50,6 @@ class OptionType(dns.enum.IntEnum): def _maximum(cls): return 65535 -globals().update(OptionType.__members__) class Option: @@ -352,3 +351,18 @@ def register_type(implementation, otype): """ _type_to_class[otype] = implementation + +### BEGIN generated OptionType constants + +NSID = OptionType.NSID +DAU = OptionType.DAU +DHU = OptionType.DHU +N3U = OptionType.N3U +ECS = OptionType.ECS +EXPIRE = OptionType.EXPIRE +COOKIE = OptionType.COOKIE +KEEPALIVE = OptionType.KEEPALIVE +PADDING = OptionType.PADDING +CHAIN = OptionType.CHAIN + +### END generated OptionType constants diff --git a/dns/flags.py b/dns/flags.py index 4eb6d90..9652287 100644 --- a/dns/flags.py +++ b/dns/flags.py @@ -37,8 +37,6 @@ class Flag(enum.IntFlag): #: Checking Disabled CD = 0x0010 -globals().update(Flag.__members__) - # EDNS flags @@ -47,9 +45,6 @@ class EDNSFlag(enum.IntFlag): DO = 0x8000 -globals().update(EDNSFlag.__members__) - - def _from_text(text, enum_class): flags = 0 tokens = text.split() @@ -104,3 +99,21 @@ def edns_to_text(flags): """ return _to_text(flags, EDNSFlag) + +### BEGIN generated Flag constants + +QR = Flag.QR +AA = Flag.AA +TC = Flag.TC +RD = Flag.RD +RA = Flag.RA +AD = Flag.AD +CD = Flag.CD + +### END generated Flag constants + +### BEGIN generated EDNSFlag constants + +DO = EDNSFlag.DO + +### END generated EDNSFlag constants diff --git a/dns/ipv6.py b/dns/ipv6.py index 5424fce..0905aaf 100644 --- a/dns/ipv6.py +++ b/dns/ipv6.py @@ -157,7 +157,7 @@ def inet_aton(text, ignore_scope=False): if seen_empty: raise dns.exception.SyntaxError seen_empty = True - for i in range(0, 8 - l + 1): + for _ in range(0, 8 - l + 1): canonical.append(b'0000') else: lc = len(c) diff --git a/dns/message.py b/dns/message.py index 52e3819..ceebdf9 100644 --- a/dns/message.py +++ b/dns/message.py @@ -107,7 +107,6 @@ class MessageSection(dns.enum.IntEnum): def _maximum(cls): return 3 -globals().update(MessageSection.__members__) DEFAULT_EDNS_PAYLOAD = 1232 MAX_CHAIN = 16 @@ -699,9 +698,13 @@ class Message: # What the caller picked is fine. return value + # pylint: disable=unused-argument + def _parse_rr_header(self, section, name, rdclass, rdtype): return (rdclass, rdtype, None, False) + # pylint: enable=unused-argument + def _parse_special_rr_header(self, section, count, position, name, rdclass, rdtype): if rdtype == dns.rdatatype.OPT: @@ -811,6 +814,8 @@ def _maybe_import_update(): # We avoid circular imports by doing this here. We do it in another # function as doing it in _message_factory_from_opcode() makes "dns" # a local symbol, and the first line fails :) + + # pylint: disable=redefined-outer-name,import-outside-toplevel,unused-import import dns.update # noqa: F401 @@ -857,7 +862,7 @@ class _WireReader: """ section = self.message.sections[section_number] - for i in range(qcount): + for _ in range(qcount): qname = self.parser.get_name(self.message.origin) (rdtype, rdclass) = self.parser.get_struct('!HH') (rdclass, rdtype, _, _) = \ @@ -1080,7 +1085,7 @@ class _TextReader: self.opcode = dns.opcode.QUERY self.flags = 0 - def _header_line(self, section): + def _header_line(self, _): """Process one line from the text format header section.""" token = self.tok.get() @@ -1459,3 +1464,12 @@ def make_response(query, recursion_available=False, our_payload=8192, tsig_error, b'', query.keyalgorithm) response.request_mac = query.mac return response + +### BEGIN generated MessageSection constants + +QUESTION = MessageSection.QUESTION +ANSWER = MessageSection.ANSWER +AUTHORITY = MessageSection.AUTHORITY +ADDITIONAL = MessageSection.ADDITIONAL + +### END generated MessageSection constants diff --git a/dns/name.py b/dns/name.py index 94d7b93..8775e0b 100644 --- a/dns/name.py +++ b/dns/name.py @@ -459,7 +459,7 @@ class Name: Returns a ``bool``. """ - (nr, o, nl) = self.fullcompare(other) + (nr, _, _) = self.fullcompare(other) if nr == NAMERELN_SUBDOMAIN or nr == NAMERELN_EQUAL: return True return False @@ -473,7 +473,7 @@ class Name: Returns a ``bool``. """ - (nr, o, nl) = self.fullcompare(other) + (nr, _, _) = self.fullcompare(other) if nr == NAMERELN_SUPERDOMAIN or nr == NAMERELN_EQUAL: return True return False diff --git a/dns/opcode.py b/dns/opcode.py index 5a76326..5cf6143 100644 --- a/dns/opcode.py +++ b/dns/opcode.py @@ -40,8 +40,6 @@ class Opcode(dns.enum.IntEnum): def _unknown_exception_class(cls): return UnknownOpcode -globals().update(Opcode.__members__) - class UnknownOpcode(dns.exception.DNSException): """An DNS opcode is unknown.""" @@ -105,3 +103,13 @@ def is_update(flags): """ return from_flags(flags) == Opcode.UPDATE + +### BEGIN generated Opcode constants + +QUERY = Opcode.QUERY +IQUERY = Opcode.IQUERY +STATUS = Opcode.STATUS +NOTIFY = Opcode.NOTIFY +UPDATE = Opcode.UPDATE + +### END generated Opcode constants diff --git a/dns/query.py b/dns/query.py index c2f619c..d4a3afa 100644 --- a/dns/query.py +++ b/dns/query.py @@ -95,10 +95,13 @@ def _compute_times(timeout): return (now, now + timeout) -def _wait_for(fd, readable, writable, error, expiration): +def _wait_for(fd, readable, writable, _, expiration): # Use the selected selector class to wait for any of the specified # events. An "expiration" absolute time is converted into a relative # timeout. + # + # The unused parameter is 'error', which is always set when + # selecting for read or write, and we have no error-only selects. if readable and isinstance(fd, ssl.SSLSocket) and fd.pending() > 0: return True @@ -278,27 +281,24 @@ def https(q, where, timeout=None, port=443, source=None, source_port=0, raise NoDOH # pragma: no cover wire = q.to_wire() - (af, destination, source) = _destination_and_source(where, port, - source, source_port, - False) + (af, _, source) = _destination_and_source(where, port, source, source_port, + False) transport_adapter = None headers = { "accept": "application/dns-message" } - try: - where_af = dns.inet.af_for_address(where) - if where_af == socket.AF_INET: + if af is not None: + if af == socket.AF_INET: url = 'https://{}:{}{}'.format(where, port, path) - elif where_af == socket.AF_INET6: + elif af == socket.AF_INET6: url = 'https://[{}]:{}{}'.format(where, port, path) - except ValueError: - if bootstrap_address is not None: - split_url = urllib.parse.urlsplit(where) - headers['Host'] = split_url.hostname - url = where.replace(split_url.hostname, bootstrap_address) - transport_adapter = HostHeaderSSLAdapter() - else: - url = where + elif bootstrap_address is not None: + split_url = urllib.parse.urlsplit(where) + headers['Host'] = split_url.hostname + url = where.replace(split_url.hostname, bootstrap_address) + transport_adapter = HostHeaderSSLAdapter() + else: + url = where if source is not None: # set source port and source address transport_adapter = SourceAddressAdapter(source) @@ -917,7 +917,7 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN, (expiration is not None and mexpiration > expiration): mexpiration = expiration if use_udp: - (wire, from_address) = _udp_recv(s, 65535, expiration) + (wire, _) = _udp_recv(s, 65535, expiration) else: ldata = _net_read(s, 2, mexpiration) (l,) = struct.unpack("!H", ldata) diff --git a/dns/rcode.py b/dns/rcode.py index 846bf6d..49fee69 100644 --- a/dns/rcode.py +++ b/dns/rcode.py @@ -72,7 +72,6 @@ class Rcode(dns.enum.IntEnum): def _unknown_exception_class(cls): return UnknownRcode -globals().update(Rcode.__members__) class UnknownRcode(dns.exception.DNSException): """A DNS rcode is unknown.""" @@ -137,3 +136,29 @@ def to_text(value, tsig=False): if tsig and value == Rcode.BADVERS: return 'BADSIG' return Rcode.to_text(value) + +### BEGIN generated Rcode constants + +NOERROR = Rcode.NOERROR +FORMERR = Rcode.FORMERR +SERVFAIL = Rcode.SERVFAIL +NXDOMAIN = Rcode.NXDOMAIN +NOTIMP = Rcode.NOTIMP +REFUSED = Rcode.REFUSED +YXDOMAIN = Rcode.YXDOMAIN +YXRRSET = Rcode.YXRRSET +NXRRSET = Rcode.NXRRSET +NOTAUTH = Rcode.NOTAUTH +NOTZONE = Rcode.NOTZONE +DSOTYPENI = Rcode.DSOTYPENI +BADVERS = Rcode.BADVERS +BADSIG = Rcode.BADSIG +BADKEY = Rcode.BADKEY +BADTIME = Rcode.BADTIME +BADMODE = Rcode.BADMODE +BADNAME = Rcode.BADNAME +BADALG = Rcode.BADALG +BADTRUNC = Rcode.BADTRUNC +BADCOOKIE = Rcode.BADCOOKIE + +### END generated Rcode constants diff --git a/dns/rdataclass.py b/dns/rdataclass.py index 7943a95..41bba69 100644 --- a/dns/rdataclass.py +++ b/dns/rdataclass.py @@ -48,7 +48,6 @@ class RdataClass(dns.enum.IntEnum): def _unknown_exception_class(cls): return UnknownRdataclass -globals().update(RdataClass.__members__) _metaclasses = {RdataClass.NONE, RdataClass.ANY} @@ -100,3 +99,17 @@ def is_metaclass(rdclass): if rdclass in _metaclasses: return True return False + +### BEGIN generated RdataClass constants + +RESERVED0 = RdataClass.RESERVED0 +IN = RdataClass.IN +INTERNET = RdataClass.INTERNET +CH = RdataClass.CH +CHAOS = RdataClass.CHAOS +HS = RdataClass.HS +HESIOD = RdataClass.HESIOD +NONE = RdataClass.NONE +ANY = RdataClass.ANY + +### END generated RdataClass constants diff --git a/dns/rdataset.py b/dns/rdataset.py index 8e70a08..0e47139 100644 --- a/dns/rdataset.py +++ b/dns/rdataset.py @@ -87,7 +87,7 @@ class Rdataset(dns.set.Set): elif ttl < self.ttl: self.ttl = ttl - def add(self, rd, ttl=None): + def add(self, rd, ttl=None): # pylint: disable=arguments-differ """Add the specified rdata to the rdataset. If the optional *ttl* parameter is supplied, then diff --git a/dns/rdatatype.py b/dns/rdatatype.py index c793d5a..740752e 100644 --- a/dns/rdatatype.py +++ b/dns/rdatatype.py @@ -115,8 +115,6 @@ class RdataType(dns.enum.IntEnum): _registered_by_text = {} _registered_by_value = {} -globals().update(RdataType.__members__) - _metatypes = {RdataType.OPT} _singletons = {RdataType.SOA, RdataType.NXT, RdataType.DNAME, @@ -219,3 +217,81 @@ def register_type(rdtype, rdtype_text, is_singleton=False): _registered_by_value[rdtype] = rdtype_text if is_singleton: _singletons.add(rdtype) + +### BEGIN generated RdataType constants + +TYPE0 = RdataType.TYPE0 +NONE = RdataType.NONE +A = RdataType.A +NS = RdataType.NS +MD = RdataType.MD +MF = RdataType.MF +CNAME = RdataType.CNAME +SOA = RdataType.SOA +MB = RdataType.MB +MG = RdataType.MG +MR = RdataType.MR +NULL = RdataType.NULL +WKS = RdataType.WKS +PTR = RdataType.PTR +HINFO = RdataType.HINFO +MINFO = RdataType.MINFO +MX = RdataType.MX +TXT = RdataType.TXT +RP = RdataType.RP +AFSDB = RdataType.AFSDB +X25 = RdataType.X25 +ISDN = RdataType.ISDN +RT = RdataType.RT +NSAP = RdataType.NSAP +NSAP_PTR = RdataType.NSAP_PTR +SIG = RdataType.SIG +KEY = RdataType.KEY +PX = RdataType.PX +GPOS = RdataType.GPOS +AAAA = RdataType.AAAA +LOC = RdataType.LOC +NXT = RdataType.NXT +SRV = RdataType.SRV +NAPTR = RdataType.NAPTR +KX = RdataType.KX +CERT = RdataType.CERT +A6 = RdataType.A6 +DNAME = RdataType.DNAME +OPT = RdataType.OPT +APL = RdataType.APL +DS = RdataType.DS +SSHFP = RdataType.SSHFP +IPSECKEY = RdataType.IPSECKEY +RRSIG = RdataType.RRSIG +NSEC = RdataType.NSEC +DNSKEY = RdataType.DNSKEY +DHCID = RdataType.DHCID +NSEC3 = RdataType.NSEC3 +NSEC3PARAM = RdataType.NSEC3PARAM +TLSA = RdataType.TLSA +HIP = RdataType.HIP +NINFO = RdataType.NINFO +CDS = RdataType.CDS +CDNSKEY = RdataType.CDNSKEY +OPENPGPKEY = RdataType.OPENPGPKEY +CSYNC = RdataType.CSYNC +SPF = RdataType.SPF +UNSPEC = RdataType.UNSPEC +EUI48 = RdataType.EUI48 +EUI64 = RdataType.EUI64 +TKEY = RdataType.TKEY +TSIG = RdataType.TSIG +IXFR = RdataType.IXFR +AXFR = RdataType.AXFR +MAILB = RdataType.MAILB +MAILA = RdataType.MAILA +ANY = RdataType.ANY +URI = RdataType.URI +CAA = RdataType.CAA +AVC = RdataType.AVC +AMTRELAY = RdataType.AMTRELAY +TA = RdataType.TA +DLV = RdataType.DLV + +### END generated RdataType constants diff --git a/dns/rdtypes/CH/A.py b/dns/rdtypes/CH/A.py index 330fcae..0cb89e2 100644 --- a/dns/rdtypes/CH/A.py +++ b/dns/rdtypes/CH/A.py @@ -15,9 +15,10 @@ # 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.mxbase import struct +import dns.rdtypes.mxbase + class A(dns.rdata.Rdata): """A record for Chaosnet""" diff --git a/dns/rdtypes/dnskeybase.py b/dns/rdtypes/dnskeybase.py index 0243d6f..935ebeb 100644 --- a/dns/rdtypes/dnskeybase.py +++ b/dns/rdtypes/dnskeybase.py @@ -31,8 +31,6 @@ class Flag(enum.IntFlag): REVOKE = 0x0080 ZONE = 0x0100 -globals().update(Flag.__members__) - class DNSKEYBase(dns.rdata.Rdata): @@ -72,3 +70,11 @@ class DNSKEYBase(dns.rdata.Rdata): key = parser.get_remaining() return cls(rdclass, rdtype, header[0], header[1], header[2], key) + +### BEGIN generated Flag constants + +SEP = Flag.SEP +REVOKE = Flag.REVOKE +ZONE = Flag.ZONE + +### END generated Flag constants diff --git a/dns/resolver.py b/dns/resolver.py index 9600c8e..eba0b44 100644 --- a/dns/resolver.py +++ b/dns/resolver.py @@ -43,6 +43,7 @@ import dns.reversename import dns.tsig if sys.platform == 'win32': + # pylint: disable=import-error import winreg class NXDOMAIN(dns.exception.DNSException): @@ -50,7 +51,10 @@ class NXDOMAIN(dns.exception.DNSException): supp_kwargs = {'qnames', 'responses'} fmt = None # we have our own __str__ implementation - def _check_kwargs(self, qnames, responses=None): + # pylint: disable=arguments-differ + + 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: @@ -161,6 +165,7 @@ class NoNameservers(dns.exception.DNSException): def _fmt_kwargs(self, **kwargs): srv_msgs = [] for err in kwargs['errors']: + # pylint: disable=bad-continuation srv_msgs.append('Server {} {} port {} answered {}'.format(err[0], 'TCP' if err[1] else 'UDP', err[2], err[3])) return super()._fmt_kwargs(query=kwargs['request'].question, @@ -854,34 +859,36 @@ class Resolver: self.search.append(dns.name.from_text(s)) def _config_win32_fromkey(self, key, always_try_domain): + # pylint: disable=undefined-variable + # (disabled for WindowsError) try: - servers, rtype = winreg.QueryValueEx(key, 'NameServer') - except WindowsError: # pylint: disable=undefined-variable + servers, _ = winreg.QueryValueEx(key, 'NameServer') + except WindowsError: # pragma: no cover servers = None if servers: self._config_win32_nameservers(servers) if servers or always_try_domain: try: - dom, rtype = winreg.QueryValueEx(key, 'Domain') + dom, _ = winreg.QueryValueEx(key, 'Domain') if dom: self._config_win32_domain(dom) # pragma: no cover except WindowsError: # pragma: no cover pass else: try: - servers, rtype = winreg.QueryValueEx(key, 'DhcpNameServer') + servers, _ = winreg.QueryValueEx(key, 'DhcpNameServer') except WindowsError: # pragma: no cover servers = None if servers: self._config_win32_nameservers(servers) try: - dom, rtype = winreg.QueryValueEx(key, 'DhcpDomain') + dom, _ = winreg.QueryValueEx(key, 'DhcpDomain') if dom: self._config_win32_domain(dom) except WindowsError: # pragma: no cover pass try: - search, rtype = winreg.QueryValueEx(key, 'SearchList') + search, _ = winreg.QueryValueEx(key, 'SearchList') except WindowsError: # pragma: no cover search = None if search: # pragma: no cover @@ -909,6 +916,7 @@ class Resolver: try: guid = winreg.EnumKey(interfaces, i) i += 1 + # XXXRTH why do we get this key and then not use it? key = winreg.OpenKey(interfaces, guid) if not self._win32_is_nic_enabled(lm, guid, key): continue @@ -923,8 +931,7 @@ class Resolver: finally: lm.Close() - def _win32_is_nic_enabled(self, lm, guid, - interface_key): + def _win32_is_nic_enabled(self, lm, guid, _): # Look in the Windows Registry to determine whether the network # interface corresponding to the given guid is enabled. # @@ -1027,7 +1034,7 @@ class Resolver: def resolve(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, tcp=False, source=None, raise_on_no_answer=True, source_port=0, - lifetime=None, search=None): + lifetime=None, search=None): # pylint: disable=arguments-differ """Query nameservers to find the answer to the question. The *qname*, *rdtype*, and *rdclass* parameters may be objects @@ -1165,6 +1172,8 @@ class Resolver: rdclass=dns.rdataclass.IN, *args, **kwargs) + # pylint: disable=redefined-outer-name + def canonical_name(self, name): """Determine the canonical name of *name*. @@ -1186,6 +1195,8 @@ class Resolver: canonical_name = e.canonical_name return canonical_name + # pylint: enable=redefined-outer-name + def use_tsig(self, keyring, keyname=None, algorithm=dns.tsig.default_algorithm): """Add a TSIG signature to each query. @@ -1405,7 +1416,7 @@ def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0, raise socket.gaierror(socket.EAI_NONAME, 'Name or service not known') v6addrs = [] v4addrs = [] - canonical_name = None + canonical_name = None # pylint: disable=redefined-outer-name # Is host None or an address literal? If so, use the system's # getaddrinfo(). if host is None: @@ -1571,7 +1582,7 @@ def _gethostbyaddr(ip): 'Name or service not known') sockaddr = (ip, 80) family = socket.AF_INET - (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD) + (name, _) = _getnameinfo(sockaddr, socket.NI_NAMEREQD) aliases = [] addresses = [] tuples = _getaddrinfo(name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP, diff --git a/dns/rrset.py b/dns/rrset.py index 68136f4..13737d3 100644 --- a/dns/rrset.py +++ b/dns/rrset.py @@ -69,13 +69,17 @@ class RRset(dns.rdataset.Rdataset): return self.to_text() def __eq__(self, other): - if not isinstance(other, RRset): - return False - if self.name != other.name: + if isinstance(other, RRset): + if self.name != other.name: + return False + elif not isinstance(other, dns.rdataset.Rdataset): return False return super().__eq__(other) - def match(self, name, rdclass, rdtype, covers, deleting=None): + # pylint: disable=arguments-differ + + def match(self, name, rdclass, rdtype, covers, + deleting=None): """Returns ``True`` if this rrset matches the specified class, type, covers, and deletion state. """ @@ -86,7 +90,8 @@ class RRset(dns.rdataset.Rdataset): return False return True - def to_text(self, origin=None, relativize=True, **kw): + def to_text(self, origin=None, relativize=True, + **kw): """Convert the RRset into DNS master file format. See ``dns.name.Name.choose_relativity`` for more information @@ -106,7 +111,8 @@ class RRset(dns.rdataset.Rdataset): return super().to_text(self.name, origin, relativize, self.deleting, **kw) - def to_wire(self, file, compress=None, origin=None, **kw): + def to_wire(self, file, compress=None, origin=None, + **kw): """Convert the RRset to wire format. All keyword arguments are passed to ``dns.rdataset.to_wire()``; see @@ -118,6 +124,8 @@ class RRset(dns.rdataset.Rdataset): return super().to_wire(self.name, file, compress, origin, self.deleting, **kw) + # pylint: enable=arguments-differ + def to_rdataset(self): """Convert an RRset into an Rdataset. diff --git a/dns/update.py b/dns/update.py index 8e79650..a541af2 100644 --- a/dns/update.py +++ b/dns/update.py @@ -38,8 +38,6 @@ class UpdateSection(dns.enum.IntEnum): def _maximum(cls): return 3 -globals().update(UpdateSection.__members__) - class UpdateMessage(dns.message.Message): @@ -310,3 +308,12 @@ class UpdateMessage(dns.message.Message): # backwards compatibility Update = UpdateMessage + +### BEGIN generated UpdateSection constants + +ZONE = UpdateSection.ZONE +PREREQ = UpdateSection.PREREQ +UPDATE = UpdateSection.UPDATE +ADDITIONAL = UpdateSection.ADDITIONAL + +### END generated UpdateSection constants diff --git a/dns/zone.py b/dns/zone.py index ad597e9..d5bb305 100644 --- a/dns/zone.py +++ b/dns/zone.py @@ -904,8 +904,10 @@ class _MasterReader: # rhs (required) rhs = token.value - lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs) - rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs) + # The code currently only supports base 'd', so the last value + # in the tuple _parse_modify returns is ignored + lmod, lsign, loffset, lwidth, _ = self._parse_modify(lhs) + rmod, rsign, roffset, rwidth, _ = self._parse_modify(rhs) for i in range(start, stop + 1, step): # +1 because bind is inclusive and python is exclusive @@ -9,7 +9,6 @@ jobs=0 enable= all, - python3 # It's worth looking at len-as-condition for optimization, but it's disabled # here as it is not a correctness thing. Similarly eq-without-hash is @@ -18,36 +17,26 @@ enable= disable= R, I, - anomalous-backslash-in-string, - arguments-differ, - assigning-non-slot, - bad-builtin, - bad-continuation, broad-except, - deprecated-method, fixme, global-statement, invalid-name, - missing-docstring, + missing-module-docstring, + missing-class-docstring, + missing-function-docstring, no-absolute-import, - no-member, + no-member, # We'd like to use this, but our immutability is too hard for it protected-access, redefined-builtin, too-many-lines, - unused-argument, - unused-variable, - wrong-import-order, - wrong-import-position, - len-as-condition, - eq-without-hash, - next-method-defined, [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. -output-format=colorized +#output-format=colorized +output-format=parseable # Tells whether to display a full report or only the messages reports=no diff --git a/tests/test_constants.py b/tests/test_constants.py new file mode 100644 index 0000000..e818bb9 --- /dev/null +++ b/tests/test_constants.py @@ -0,0 +1,38 @@ +# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license + +import unittest + +import dns.dnssec +import dns.rdtypes.dnskeybase +import dns.flags +import dns.rcode +import dns.opcode +import dns.message +import dns.update +import dns.edns + +import tests.util + + +class ConstantsTestCase(unittest.TestCase): + + def test_dnssec_constants(self): + tests.util.check_enum_exports(dns.dnssec, self.assertEqual, + only={dns.dnssec.Algorithm}) + tests.util.check_enum_exports(dns.rdtypes.dnskeybase, self.assertEqual) + + def test_flags_constants(self): + tests.util.check_enum_exports(dns.flags, self.assertEqual) + tests.util.check_enum_exports(dns.rcode, self.assertEqual) + tests.util.check_enum_exports(dns.opcode, self.assertEqual) + + def test_message_constants(self): + tests.util.check_enum_exports(dns.message, self.assertEqual) + tests.util.check_enum_exports(dns.update, self.assertEqual) + + def test_rdata_constants(self): + tests.util.check_enum_exports(dns.rdataclass, self.assertEqual) + tests.util.check_enum_exports(dns.rdatatype, self.assertEqual) + + def test_edns_constants(self): + tests.util.check_enum_exports(dns.edns, self.assertEqual) diff --git a/tests/util.py b/tests/util.py index df736df..644a88a 100644 --- a/tests/util.py +++ b/tests/util.py @@ -15,7 +15,26 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +import enum +import inspect import os.path def here(filename): return os.path.join(os.path.dirname(__file__), filename) + +def enumerate_module(module, super_class): + """Yield module attributes which are subclasses of given class""" + for attr_name in dir(module): + attr = getattr(module, attr_name) + if inspect.isclass(attr) and issubclass(attr, super_class): + yield attr + +def check_enum_exports(module, eq_callback, only=None): + """Make sure module exports all mnemonics from enums""" + for attr in enumerate_module(module, enum.Enum): + if only is not None and attr not in only: + print('SKIP', attr) + continue + for flag, value in attr.__members__.items(): + print(module, flag, value) + eq_callback(getattr(module, flag), value) diff --git a/util/constants-tool b/util/constants-tool new file mode 100755 index 0000000..0fc7cd4 --- /dev/null +++ b/util/constants-tool @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license + +from importlib import import_module +import os +import sys + +enum_names = [ + 'dns.dnssec.Algorithm', + 'dns.edns.OptionType', + 'dns.flags.Flag', + 'dns.flags.EDNSFlag', + 'dns.message.MessageSection', + 'dns.opcode.Opcode', + 'dns.rcode.Rcode', + 'dns.rdataclass.RdataClass', + 'dns.rdatatype.RdataType', + 'dns.rdtypes.dnskeybase.Flag', + 'dns.update.UpdateSection', +] + +def generate(): + for enum_name in enum_names: + dot = enum_name.rindex('.') + module_name = enum_name[:dot] + type_name = enum_name[dot + 1:] + lname = type_name.lower() + mod = import_module(module_name) + enum = getattr(mod, type_name) + filename = module_name.replace('.', '/') + '.py' + new_filename = filename + '.new' + with open(filename) as f: + with open(new_filename, 'w') as nf: + lines = f.readlines() + found = False + i = 0 + length = len(lines) + while i < length: + l = lines[i].rstrip() + i += 1 + if l.startswith(f'### BEGIN generated {type_name} ' + + 'constants') or \ + l.startswith(f'### BEGIN generated {lname} constants'): + found = True + break + else: + print(l, file=nf) + if found: + found = False + while i < length: + l = lines[i].rstrip() + i += 1 + if l.startswith(f'### END generated {type_name} ' + + 'constants') or \ + l.startswith(f'### END generated {lname} constants'): + found = True + break + if not found: + print(f'Found begin marker for {type_name} but did ' + + 'not find end marker!', file=sys.stderr) + sys.exit(1) + if not found: + print('', file=nf) + print(f'### BEGIN generated {type_name} constants', file=nf) + print('', file=nf) + # We have to use __members__.items() and not "in enum" because + # otherwise we miss values that have multiple names (e.g. NONE + # and TYPE0 for rdatatypes). + for name, value in enum.__members__.items(): + print(f'{name} = {type_name}.{name}', file=nf) + print('', file=nf) + print(f'### END generated {type_name} constants', file=nf) + # Copy remaining lines (if any) + while i < length: + l = lines[i].rstrip() + i += 1 + print(l, file=nf) + os.rename(new_filename, filename) + +def main(): + generate() + +if __name__ == '__main__': + main() |