From 82bc428366df9694ce0b4cfb7d4503e9d0c38248 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Mon, 3 Aug 2020 06:35:22 -0700 Subject: [PATCH 1/6] add constants --- dns/dnssec.py | 22 ++++++++ dns/edns.py | 15 +++++ dns/flags.py | 18 ++++++ dns/message.py | 9 +++ dns/opcode.py | 10 ++++ dns/rcode.py | 26 +++++++++ dns/rdataclass.py | 14 +++++ dns/rdatatype.py | 78 ++++++++++++++++++++++++++ dns/rdtypes/dnskeybase.py | 8 +++ dns/update.py | 9 +++ util/constants-tool | 112 ++++++++++++++++++++++++++++++++++++++ 11 files changed, 321 insertions(+) create mode 100755 util/constants-tool diff --git a/dns/dnssec.py b/dns/dnssec.py index 891999661..79752aae1 100644 --- a/dns/dnssec.py +++ b/dns/dnssec.py @@ -584,3 +584,25 @@ def _need_pyca(*args, **kwargs): 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 087592b56..75ecdf182 100644 --- a/dns/edns.py +++ b/dns/edns.py @@ -352,3 +352,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 4eb6d90cc..a53197c79 100644 --- a/dns/flags.py +++ b/dns/flags.py @@ -104,3 +104,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/message.py b/dns/message.py index 1dfb0280f..1a5787f75 100644 --- a/dns/message.py +++ b/dns/message.py @@ -1465,3 +1465,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/opcode.py b/dns/opcode.py index 5a76326a7..32f209fa2 100644 --- a/dns/opcode.py +++ b/dns/opcode.py @@ -105,3 +105,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/rcode.py b/dns/rcode.py index 846bf6dcd..6e33045b0 100644 --- a/dns/rcode.py +++ b/dns/rcode.py @@ -137,3 +137,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 7943a95a8..af0bd9976 100644 --- a/dns/rdataclass.py +++ b/dns/rdataclass.py @@ -100,3 +100,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/rdatatype.py b/dns/rdatatype.py index c793d5a0d..1abc59c9a 100644 --- a/dns/rdatatype.py +++ b/dns/rdatatype.py @@ -219,3 +219,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/dnskeybase.py b/dns/rdtypes/dnskeybase.py index 0243d6f33..1fac4bdc4 100644 --- a/dns/rdtypes/dnskeybase.py +++ b/dns/rdtypes/dnskeybase.py @@ -72,3 +72,11 @@ def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): 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/update.py b/dns/update.py index 8e796504f..b4cb755a6 100644 --- a/dns/update.py +++ b/dns/update.py @@ -310,3 +310,12 @@ def _parse_rr_header(self, section, name, rdclass, rdtype): # 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/util/constants-tool b/util/constants-tool new file mode 100755 index 000000000..baf54b65c --- /dev/null +++ b/util/constants-tool @@ -0,0 +1,112 @@ +#!/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:] + 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'): + 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'): + 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 check(): + ok = True + for enum_name in enum_names: + dot = enum_name.rindex('.') + module_name = enum_name[:dot] + type_name = enum_name[dot + 1:] + mod = import_module(module_name) + enum = getattr(mod, type_name) + for name, value in enum.__members__.items(): + try: + if value != getattr(mod, name): + ok = False + print(f'{name} != {value}', file=sys.stderr) + except Exception: + ok = False + print('exception checking', name, file=sys.stderr) + return ok + +def usage(): + print('usage: constants-tool [generate|check]', file=sys.stderr) + sys.exit(1) + +def main(): + if len(sys.argv) < 2: + usage() + if sys.argv[1] == 'generate': + generate() + elif sys.argv[1] == 'check': + if not check(): + sys.exit(2) + else: + usage() + +if __name__ == '__main__': + main() From e7c090a0b1831525a098e9d61cf76111050eee40 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Mon, 3 Aug 2020 06:41:31 -0700 Subject: [PATCH 2/6] remove globals() enum updating --- dns/dnssec.py | 3 --- dns/edns.py | 1 - dns/flags.py | 5 ----- dns/message.py | 1 - dns/opcode.py | 2 -- dns/rcode.py | 1 - dns/rdataclass.py | 1 - dns/rdatatype.py | 2 -- dns/rdtypes/dnskeybase.py | 2 -- dns/update.py | 2 -- 10 files changed, 20 deletions(-) diff --git a/dns/dnssec.py b/dns/dnssec.py index 79752aae1..ada7d1a3b 100644 --- a/dns/dnssec.py +++ b/dns/dnssec.py @@ -64,9 +64,6 @@ def _maximum(cls): return 255 -globals().update(Algorithm.__members__) - - def algorithm_from_text(text): """Convert text into a DNSSEC algorithm value. diff --git a/dns/edns.py b/dns/edns.py index 75ecdf182..1342d1eb8 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: diff --git a/dns/flags.py b/dns/flags.py index a53197c79..20e62473e 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() diff --git a/dns/message.py b/dns/message.py index 1a5787f75..9401996e8 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 diff --git a/dns/opcode.py b/dns/opcode.py index 32f209fa2..d5df57fac 100644 --- a/dns/opcode.py +++ b/dns/opcode.py @@ -40,8 +40,6 @@ def _maximum(cls): def _unknown_exception_class(cls): return UnknownOpcode -globals().update(Opcode.__members__) - class UnknownOpcode(dns.exception.DNSException): """An DNS opcode is unknown.""" diff --git a/dns/rcode.py b/dns/rcode.py index 6e33045b0..8b6562e2f 100644 --- a/dns/rcode.py +++ b/dns/rcode.py @@ -72,7 +72,6 @@ def _maximum(cls): def _unknown_exception_class(cls): return UnknownRcode -globals().update(Rcode.__members__) class UnknownRcode(dns.exception.DNSException): """A DNS rcode is unknown.""" diff --git a/dns/rdataclass.py b/dns/rdataclass.py index af0bd9976..564c3ecb6 100644 --- a/dns/rdataclass.py +++ b/dns/rdataclass.py @@ -48,7 +48,6 @@ def _prefix(cls): def _unknown_exception_class(cls): return UnknownRdataclass -globals().update(RdataClass.__members__) _metaclasses = {RdataClass.NONE, RdataClass.ANY} diff --git a/dns/rdatatype.py b/dns/rdatatype.py index 1abc59c9a..62f51f8ae 100644 --- a/dns/rdatatype.py +++ b/dns/rdatatype.py @@ -115,8 +115,6 @@ def _unknown_exception_class(cls): _registered_by_text = {} _registered_by_value = {} -globals().update(RdataType.__members__) - _metatypes = {RdataType.OPT} _singletons = {RdataType.SOA, RdataType.NXT, RdataType.DNAME, diff --git a/dns/rdtypes/dnskeybase.py b/dns/rdtypes/dnskeybase.py index 1fac4bdc4..f9f8c8466 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): diff --git a/dns/update.py b/dns/update.py index b4cb755a6..227d74f0f 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): From acc9a1dab2c1cf9d4b150b9f4f2554de54dfcf33 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Mon, 3 Aug 2020 06:44:42 -0700 Subject: [PATCH 3/6] multiple # in a comment is ok --- .flake8 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.flake8 b/.flake8 index a294638fc..3b1f77dec 100644 --- a/.flake8 +++ b/.flake8 @@ -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, From 76bfd7f0ba49e6c6937b4473f867b7dfafaf2107 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Mon, 3 Aug 2020 07:00:38 -0700 Subject: [PATCH 4/6] fix case of enum names --- dns/dnssec.py | 4 ++-- dns/edns.py | 4 ++-- dns/flags.py | 8 ++++---- dns/message.py | 4 ++-- dns/opcode.py | 4 ++-- dns/rcode.py | 4 ++-- dns/rdataclass.py | 4 ++-- dns/rdatatype.py | 4 ++-- dns/rdtypes/dnskeybase.py | 4 ++-- dns/update.py | 4 ++-- util/constants-tool | 7 +++++-- 11 files changed, 27 insertions(+), 24 deletions(-) diff --git a/dns/dnssec.py b/dns/dnssec.py index ada7d1a3b..095fabd45 100644 --- a/dns/dnssec.py +++ b/dns/dnssec.py @@ -582,7 +582,7 @@ def _need_pyca(*args, **kwargs): validate_rrsig = _validate_rrsig # type: ignore _have_pyca = True -### BEGIN generated algorithm constants +### BEGIN generated Algorithm constants RSAMD5 = Algorithm.RSAMD5 DH = Algorithm.DH @@ -602,4 +602,4 @@ def _need_pyca(*args, **kwargs): PRIVATEDNS = Algorithm.PRIVATEDNS PRIVATEOID = Algorithm.PRIVATEOID -### END generated algorithm constants +### END generated Algorithm constants diff --git a/dns/edns.py b/dns/edns.py index 1342d1eb8..199e8c486 100644 --- a/dns/edns.py +++ b/dns/edns.py @@ -352,7 +352,7 @@ def register_type(implementation, otype): _type_to_class[otype] = implementation -### BEGIN generated optiontype constants +### BEGIN generated OptionType constants NSID = OptionType.NSID DAU = OptionType.DAU @@ -365,4 +365,4 @@ def register_type(implementation, otype): PADDING = OptionType.PADDING CHAIN = OptionType.CHAIN -### END generated optiontype constants +### END generated OptionType constants diff --git a/dns/flags.py b/dns/flags.py index 20e62473e..965228798 100644 --- a/dns/flags.py +++ b/dns/flags.py @@ -100,7 +100,7 @@ def edns_to_text(flags): return _to_text(flags, EDNSFlag) -### BEGIN generated flag constants +### BEGIN generated Flag constants QR = Flag.QR AA = Flag.AA @@ -110,10 +110,10 @@ def edns_to_text(flags): AD = Flag.AD CD = Flag.CD -### END generated flag constants +### END generated Flag constants -### BEGIN generated ednsflag constants +### BEGIN generated EDNSFlag constants DO = EDNSFlag.DO -### END generated ednsflag constants +### END generated EDNSFlag constants diff --git a/dns/message.py b/dns/message.py index 9401996e8..ceebdf9c1 100644 --- a/dns/message.py +++ b/dns/message.py @@ -1465,11 +1465,11 @@ def make_response(query, recursion_available=False, our_payload=8192, response.request_mac = query.mac return response -### BEGIN generated messagesection constants +### BEGIN generated MessageSection constants QUESTION = MessageSection.QUESTION ANSWER = MessageSection.ANSWER AUTHORITY = MessageSection.AUTHORITY ADDITIONAL = MessageSection.ADDITIONAL -### END generated messagesection constants +### END generated MessageSection constants diff --git a/dns/opcode.py b/dns/opcode.py index d5df57fac..5cf6143c7 100644 --- a/dns/opcode.py +++ b/dns/opcode.py @@ -104,7 +104,7 @@ def is_update(flags): return from_flags(flags) == Opcode.UPDATE -### BEGIN generated opcode constants +### BEGIN generated Opcode constants QUERY = Opcode.QUERY IQUERY = Opcode.IQUERY @@ -112,4 +112,4 @@ def is_update(flags): NOTIFY = Opcode.NOTIFY UPDATE = Opcode.UPDATE -### END generated opcode constants +### END generated Opcode constants diff --git a/dns/rcode.py b/dns/rcode.py index 8b6562e2f..49fee6950 100644 --- a/dns/rcode.py +++ b/dns/rcode.py @@ -137,7 +137,7 @@ def to_text(value, tsig=False): return 'BADSIG' return Rcode.to_text(value) -### BEGIN generated rcode constants +### BEGIN generated Rcode constants NOERROR = Rcode.NOERROR FORMERR = Rcode.FORMERR @@ -161,4 +161,4 @@ def to_text(value, tsig=False): BADTRUNC = Rcode.BADTRUNC BADCOOKIE = Rcode.BADCOOKIE -### END generated rcode constants +### END generated Rcode constants diff --git a/dns/rdataclass.py b/dns/rdataclass.py index 564c3ecb6..41bba693b 100644 --- a/dns/rdataclass.py +++ b/dns/rdataclass.py @@ -100,7 +100,7 @@ def is_metaclass(rdclass): return True return False -### BEGIN generated rdataclass constants +### BEGIN generated RdataClass constants RESERVED0 = RdataClass.RESERVED0 IN = RdataClass.IN @@ -112,4 +112,4 @@ def is_metaclass(rdclass): NONE = RdataClass.NONE ANY = RdataClass.ANY -### END generated rdataclass constants +### END generated RdataClass constants diff --git a/dns/rdatatype.py b/dns/rdatatype.py index 62f51f8ae..740752ebe 100644 --- a/dns/rdatatype.py +++ b/dns/rdatatype.py @@ -218,7 +218,7 @@ def register_type(rdtype, rdtype_text, is_singleton=False): if is_singleton: _singletons.add(rdtype) -### BEGIN generated rdatatype constants +### BEGIN generated RdataType constants TYPE0 = RdataType.TYPE0 NONE = RdataType.NONE @@ -294,4 +294,4 @@ def register_type(rdtype, rdtype_text, is_singleton=False): TA = RdataType.TA DLV = RdataType.DLV -### END generated rdatatype constants +### END generated RdataType constants diff --git a/dns/rdtypes/dnskeybase.py b/dns/rdtypes/dnskeybase.py index f9f8c8466..935ebeb2b 100644 --- a/dns/rdtypes/dnskeybase.py +++ b/dns/rdtypes/dnskeybase.py @@ -71,10 +71,10 @@ def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): return cls(rdclass, rdtype, header[0], header[1], header[2], key) -### BEGIN generated flag constants +### BEGIN generated Flag constants SEP = Flag.SEP REVOKE = Flag.REVOKE ZONE = Flag.ZONE -### END generated flag constants +### END generated Flag constants diff --git a/dns/update.py b/dns/update.py index 227d74f0f..a541af22d 100644 --- a/dns/update.py +++ b/dns/update.py @@ -309,11 +309,11 @@ def _parse_rr_header(self, section, name, rdclass, rdtype): # backwards compatibility Update = UpdateMessage -### BEGIN generated updatesection constants +### BEGIN generated UpdateSection constants ZONE = UpdateSection.ZONE PREREQ = UpdateSection.PREREQ UPDATE = UpdateSection.UPDATE ADDITIONAL = UpdateSection.ADDITIONAL -### END generated updatesection constants +### END generated UpdateSection constants diff --git a/util/constants-tool b/util/constants-tool index baf54b65c..bd843fa87 100755 --- a/util/constants-tool +++ b/util/constants-tool @@ -25,6 +25,7 @@ def generate(): 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' @@ -39,7 +40,8 @@ def generate(): l = lines[i].rstrip() i += 1 if l.startswith(f'### BEGIN generated {type_name} ' + - 'constants'): + 'constants') or \ + l.startswith(f'### BEGIN generated {lname} constants'): found = True break else: @@ -50,7 +52,8 @@ def generate(): l = lines[i].rstrip() i += 1 if l.startswith(f'### END generated {type_name} ' + - 'constants'): + 'constants') or \ + l.startswith(f'### END generated {lname} constants'): found = True break if not found: From b70e664ff050b30d2fe40ee041b102fa240827eb Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Tue, 4 Aug 2020 06:05:00 -0700 Subject: [PATCH 5/6] add enumeration checking helpers --- tests/util.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/util.py b/tests/util.py index df736df05..644a88a10 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) From c33265d94c275978169174a460de2c1fa0f1d517 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Tue, 4 Aug 2020 06:05:19 -0700 Subject: [PATCH 6/6] test constants with independent code --- tests/test_constants.py | 38 ++++++++++++++++++++++++++++++++++++++ util/constants-tool | 32 +------------------------------- 2 files changed, 39 insertions(+), 31 deletions(-) create mode 100644 tests/test_constants.py diff --git a/tests/test_constants.py b/tests/test_constants.py new file mode 100644 index 000000000..e818bb9bc --- /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/util/constants-tool b/util/constants-tool index bd843fa87..0fc7cd416 100755 --- a/util/constants-tool +++ b/util/constants-tool @@ -78,38 +78,8 @@ def generate(): print(l, file=nf) os.rename(new_filename, filename) -def check(): - ok = True - for enum_name in enum_names: - dot = enum_name.rindex('.') - module_name = enum_name[:dot] - type_name = enum_name[dot + 1:] - mod = import_module(module_name) - enum = getattr(mod, type_name) - for name, value in enum.__members__.items(): - try: - if value != getattr(mod, name): - ok = False - print(f'{name} != {value}', file=sys.stderr) - except Exception: - ok = False - print('exception checking', name, file=sys.stderr) - return ok - -def usage(): - print('usage: constants-tool [generate|check]', file=sys.stderr) - sys.exit(1) - def main(): - if len(sys.argv) < 2: - usage() - if sys.argv[1] == 'generate': - generate() - elif sys.argv[1] == 'check': - if not check(): - sys.exit(2) - else: - usage() + generate() if __name__ == '__main__': main()