From 40ff526586aa52b52721df8977f0e73c69dfe4c2 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Fri, 3 Jul 2026 08:18:39 -0700 Subject: [PATCH] Fix other isdigit() instances that are better as isdecimal(). Both raised exceptions, but the latter raises a dns.exception.SyntaxError in cases where the old code raised ValueError. This change also fixes the tokenizer's get_int() method, which did not work for bases bigger than 10. --- dns/e164.py | 2 +- dns/enum.py | 2 +- dns/flags.py | 2 +- dns/grange.py | 2 +- dns/inet.py | 2 +- dns/name.py | 4 ++-- dns/rdtypes/ANY/GPOS.py | 4 ++-- dns/rdtypes/ANY/LOC.py | 16 ++++++++-------- dns/rdtypes/IN/WKS.py | 4 ++-- dns/rdtypes/rrsigbase.py | 2 +- dns/rdtypes/svcbbase.py | 4 ++-- dns/tokenizer.py | 16 ++++++++++------ tests/test_tokenizer.py | 3 +++ 13 files changed, 35 insertions(+), 28 deletions(-) diff --git a/dns/e164.py b/dns/e164.py index c0ac3e1c..321eda40 100644 --- a/dns/e164.py +++ b/dns/e164.py @@ -44,7 +44,7 @@ def from_e164( :rtype: :py:class:`dns.name.Name` """ - parts = [d for d in text if d.isdigit()] + parts = [d for d in text if d.isdecimal()] parts.reverse() return dns.name.from_text(".".join(parts), origin=origin) diff --git a/dns/enum.py b/dns/enum.py index ca3c62f0..604421c0 100644 --- a/dns/enum.py +++ b/dns/enum.py @@ -50,7 +50,7 @@ class IntEnum(enum.IntEnum): if value: return value prefix = cls._prefix() - if text.startswith(prefix) and text[len(prefix) :].isdigit(): + if text.startswith(prefix) and text[len(prefix) :].isdecimal(): value = int(text[len(prefix) :]) cls._check_value(value) return cls(value) diff --git a/dns/flags.py b/dns/flags.py index 9fd1d0e6..4317a6e7 100644 --- a/dns/flags.py +++ b/dns/flags.py @@ -62,7 +62,7 @@ def _from_text(text: str, enum_class: Any) -> int: tokens = text.split() for t in tokens: token = t.upper() - if token.startswith("FLAG") and token[4:].isdigit(): + if token.startswith("FLAG") and token[4:].isdecimal(): # An unnamed flag, rendered by _to_text() as FLAGn (see below). flags |= 1 << int(token[4:]) else: diff --git a/dns/grange.py b/dns/grange.py index 7a217f8d..bbfa9d94 100644 --- a/dns/grange.py +++ b/dns/grange.py @@ -49,7 +49,7 @@ def from_text(text: str) -> tuple[int, int, int]: stop = int(cur) cur = "" state = 2 - elif c.isdigit(): + elif c.isdecimal(): cur += c else: raise dns.exception.SyntaxError(f"Could not parse {c}") diff --git a/dns/inet.py b/dns/inet.py index 8d80c2f9..764309a8 100644 --- a/dns/inet.py +++ b/dns/inet.py @@ -149,7 +149,7 @@ def low_level_address_tuple(high_tuple: tuple[str, int], af: int | None = None) # try to avoid getaddrinfo() addrpart = address[:i] scope = address[i + 1 :] - if scope.isdigit(): + if scope.isdecimal(): return (addrpart, port, 0, int(scope)) try: return (addrpart, port, 0, socket.if_nametoindex(scope)) diff --git a/dns/name.py b/dns/name.py index aeb50682..526e539d 100644 --- a/dns/name.py +++ b/dns/name.py @@ -1004,14 +1004,14 @@ def from_unicode( for c in text: if escaping: if edigits == 0: - if c.isdigit(): + if c.isdecimal(): total = int(c) edigits += 1 else: label += c escaping = False else: - if not c.isdigit(): + if not c.isdecimal(): raise BadEscape total *= 10 total += int(c) diff --git a/dns/rdtypes/ANY/GPOS.py b/dns/rdtypes/ANY/GPOS.py index 8a6caea3..7eb8fcfc 100644 --- a/dns/rdtypes/ANY/GPOS.py +++ b/dns/rdtypes/ANY/GPOS.py @@ -36,9 +36,9 @@ def _validate_float_string(what): raise dns.exception.FormError if left == b"" and right == b"": raise dns.exception.FormError - if not left == b"" and not left.decode().isdigit(): + if not left == b"" and not left.isdigit(): raise dns.exception.FormError - if not right == b"" and not right.decode().isdigit(): + if not right == b"" and not right.isdigit(): raise dns.exception.FormError diff --git a/dns/rdtypes/ANY/LOC.py b/dns/rdtypes/ANY/LOC.py index 02b0a2c3..f377cee6 100644 --- a/dns/rdtypes/ANY/LOC.py +++ b/dns/rdtypes/ANY/LOC.py @@ -196,16 +196,16 @@ class LOC(dns.rdata.Rdata): latitude[0] = tok.get_int() t = tok.get_string() - if t.isdigit(): + if t.isdecimal(): latitude[1] = int(t) t = tok.get_string() if "." in t: seconds, milliseconds = t.split(".") - if not seconds.isdigit(): + if not seconds.isdecimal(): raise dns.exception.SyntaxError("bad latitude seconds value") latitude[2] = int(seconds) l = len(milliseconds) - if l == 0 or l > 3 or not milliseconds.isdigit(): + if l == 0 or l > 3 or not milliseconds.isdecimal(): raise dns.exception.SyntaxError("bad latitude milliseconds value") if l == 1: m = 100 @@ -215,7 +215,7 @@ class LOC(dns.rdata.Rdata): m = 1 latitude[3] = m * int(milliseconds) t = tok.get_string() - elif t.isdigit(): + elif t.isdecimal(): latitude[2] = int(t) t = tok.get_string() if t == "S": @@ -225,16 +225,16 @@ class LOC(dns.rdata.Rdata): longitude[0] = tok.get_int() t = tok.get_string() - if t.isdigit(): + if t.isdecimal(): longitude[1] = int(t) t = tok.get_string() if "." in t: seconds, milliseconds = t.split(".") - if not seconds.isdigit(): + if not seconds.isdecimal(): raise dns.exception.SyntaxError("bad longitude seconds value") longitude[2] = int(seconds) l = len(milliseconds) - if l == 0 or l > 3 or not milliseconds.isdigit(): + if l == 0 or l > 3 or not milliseconds.isdecimal(): raise dns.exception.SyntaxError("bad longitude milliseconds value") if l == 1: m = 100 @@ -244,7 +244,7 @@ class LOC(dns.rdata.Rdata): m = 1 longitude[3] = m * int(milliseconds) t = tok.get_string() - elif t.isdigit(): + elif t.isdecimal(): longitude[2] = int(t) t = tok.get_string() if t == "W": diff --git a/dns/rdtypes/IN/WKS.py b/dns/rdtypes/IN/WKS.py index 634386fc..1ab7dba5 100644 --- a/dns/rdtypes/IN/WKS.py +++ b/dns/rdtypes/IN/WKS.py @@ -60,14 +60,14 @@ class WKS(dns.rdata.Rdata): ): address = tok.get_string() protocol = tok.get_string() - if protocol.isdigit(): + if protocol.isdecimal(): protocol = int(protocol) else: protocol = socket.getprotobyname(protocol) bitmap = bytearray() for token in tok.get_remaining(): value = token.unescape().value - if value.isdigit(): + if value.isdecimal(): serv = int(value) else: if protocol != _proto_udp and protocol != _proto_tcp: diff --git a/dns/rdtypes/rrsigbase.py b/dns/rdtypes/rrsigbase.py index 2b7208fd..d65ef396 100644 --- a/dns/rdtypes/rrsigbase.py +++ b/dns/rdtypes/rrsigbase.py @@ -34,7 +34,7 @@ class BadSigTime(dns.exception.DNSException): def sigtime_to_posixtime(what): - if len(what) <= 10 and what.isdigit(): + if len(what) <= 10 and what.isdecimal(): return int(what) if len(what) != 14: raise BadSigTime diff --git a/dns/rdtypes/svcbbase.py b/dns/rdtypes/svcbbase.py index c97adda6..0acdd646 100644 --- a/dns/rdtypes/svcbbase.py +++ b/dns/rdtypes/svcbbase.py @@ -113,7 +113,7 @@ def _unescape(value: str) -> bytes: raise dns.exception.UnexpectedEnd c = value[i] i += 1 - if c.isdigit(): + if c.isdecimal(): if i >= l: raise dns.exception.UnexpectedEnd c2 = value[i] @@ -122,7 +122,7 @@ def _unescape(value: str) -> bytes: raise dns.exception.UnexpectedEnd c3 = value[i] i += 1 - if not (c2.isdigit() and c3.isdigit()): + if not (c2.isdecimal() and c3.isdecimal()): raise dns.exception.SyntaxError codepoint = int(c) * 100 + int(c2) * 10 + int(c3) if codepoint > 255: diff --git a/dns/tokenizer.py b/dns/tokenizer.py index 42bf45c3..5c0638e5 100644 --- a/dns/tokenizer.py +++ b/dns/tokenizer.py @@ -114,7 +114,7 @@ class Token: raise dns.exception.UnexpectedEnd c = self.value[i] i += 1 - if c.isdigit(): + if c.isdecimal(): if i >= l: raise dns.exception.UnexpectedEnd c2 = self.value[i] @@ -123,7 +123,7 @@ class Token: raise dns.exception.UnexpectedEnd c3 = self.value[i] i += 1 - if not (c2.isdigit() and c3.isdigit()): + if not (c2.isdecimal() and c3.isdecimal()): raise dns.exception.SyntaxError codepoint = int(c) * 100 + int(c2) * 10 + int(c3) if codepoint > 255: @@ -168,7 +168,7 @@ class Token: raise dns.exception.UnexpectedEnd c = self.value[i] i += 1 - if c.isdigit(): + if c.isdecimal(): if i >= l: raise dns.exception.UnexpectedEnd c2 = self.value[i] @@ -177,7 +177,7 @@ class Token: raise dns.exception.UnexpectedEnd c3 = self.value[i] i += 1 - if not (c2.isdigit() and c3.isdigit()): + if not (c2.isdecimal() and c3.isdecimal()): raise dns.exception.SyntaxError codepoint = int(c) * 100 + int(c2) * 10 + int(c3) if codepoint > 255: @@ -631,9 +631,13 @@ class Tokenizer: if not token.is_identifier(): raise dns.exception.SyntaxError("expecting an identifier") - if not token.value.isdigit(): + try: + value = int(token.value, base) + if value < 0: + raise ValueError + except ValueError: raise dns.exception.SyntaxError("expecting an integer") - return int(token.value, base) + return value def as_uint8(self, token: Token) -> int: """Try to interpret the token as an unsigned 8-bit integer. diff --git a/tests/test_tokenizer.py b/tests/test_tokenizer.py index d8b1723d..392b1e4d 100644 --- a/tests/test_tokenizer.py +++ b/tests/test_tokenizer.py @@ -238,6 +238,9 @@ class TokenizerTestCase(unittest.TestCase): with self.assertRaises(dns.exception.SyntaxError): tok = dns.tokenizer.Tokenizer("200000") tok.get_uint16(base=8) + tok = dns.tokenizer.Tokenizer("ff") + v = tok.get_int(16) + self.assertEqual(v, 255) def testGetString(self): tok = dns.tokenizer.Tokenizer("foo") -- 2.47.3