]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
IDNA default improvements
authorBob Halley <halley@dnspython.org>
Sat, 7 Feb 2026 15:14:14 +0000 (07:14 -0800)
committerGitHub <noreply@github.com>
Sat, 7 Feb 2026 15:14:14 +0000 (07:14 -0800)
* If idna is available, make IDNA_2008_Practical the default idna_codec.

* Add a way to set the default IDNA codec.

dns/name.py
tests/test_name.py
tests/test_rrset.py

index cfdf2d6479de445cdac87be95e709f85f698f843..e705126ddd386ae9d98955576daffe6aab907167 100644 (file)
@@ -316,6 +316,15 @@ 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
+if have_idna_2008:
+    IDNA_DEFAULT = IDNA_2008_Practical
+else:
+    IDNA_DEFAULT = IDNA_2003_Practical
+
+
+def set_default_idna_codec(idna_codec: IDNACodec):
+    global IDNA_DEFAULT
+    IDNA_DEFAULT = idna_codec
 
 
 def _validate_labels(labels: tuple[bytes, ...]) -> None:
@@ -605,11 +614,7 @@ class Name:
         dot (denoting the root label) for absolute names.  The default
         is False.
         *idna_codec* specifies the IDNA encoder/decoder.  If None, the
-        dns.name.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.
+        dns.name.IDNA_DEFAULT encoder/decoder is used.
 
         Returns a ``str``.
         """
@@ -623,7 +628,7 @@ class Name:
         else:
             l = self.labels
         if idna_codec is None:
-            idna_codec = IDNA_2003_Practical
+            idna_codec = IDNA_DEFAULT
         return ".".join([idna_codec.decode(x) for x in l])
 
     def to_digestable(self, origin: "Name | None" = None) -> bytes:
@@ -924,7 +929,7 @@ def from_unicode(
     edigits = 0
     total = 0
     if idna_codec is None:
-        idna_codec = IDNA_2003
+        idna_codec = IDNA_DEFAULT
     if text == "@":
         text = ""
     if text:
index 0addb821791717b472cfed5bc1595fbe1d66cef0..40a409c3e1302da766b77d43a4ce2d91bf23568c 100644 (file)
@@ -804,11 +804,6 @@ class NameTestCase(unittest.TestCase):
         e = dns.name.from_unicode(t, idna_codec=dns.name.IDNA_2003)
         self.assertEqual(str(e), "xn--knigsgsschen-lcb0w.")
 
-    def testFromUnicodeIDNA2003Default(self):
-        t = "Königsgäßchen"
-        e = dns.name.from_unicode(t)
-        self.assertEqual(str(e), "xn--knigsgsschen-lcb0w.")
-
     @unittest.skipUnless(
         dns.name.have_idna_2008, "Python idna cannot be imported; no IDNA2008"
     )
@@ -1145,10 +1140,19 @@ class NameTestCase(unittest.TestCase):
         with self.assertRaises(TypeError):
             del n.labels
 
-    def testUnicodeEscapify(self):
-        n = dns.name.from_unicode("Königsgäßchen;\ttext")
+    def testUnicodeEscapify2003(self):
+        n = dns.name.from_unicode("Königsgäßchen;\ttext", idna_codec=dns.name.IDNA_2003)
         self.assertEqual(n.to_unicode(), "königsgässchen\\;\\009text.")
 
+    @unittest.skipUnless(
+        dns.name.have_idna_2008, "Python idna cannot be imported; no IDNA2008"
+    )
+    def testUnicodeEscapify2008(self):
+        def bad():
+            dns.name.from_unicode("Königsgäßchen;\ttext", idna_codec=dns.name.IDNA_2008)
+
+        self.assertRaises(dns.name.IDNAException, bad)
+
     def test_pickle(self):
         n1 = dns.name.from_text("foo.example")
         p = pickle.dumps(n1)
index 23e33bb96c4bfa366e6765631c34dbf10ff1a856..8d1eb6faccb795835c3173e6afc1f1c57333eda0 100644 (file)
@@ -57,10 +57,20 @@ class RRsetTestCase(unittest.TestCase):
 
     def testCodec2003(self):
         r1 = dns.rrset.from_text_list(
-            "Königsgäßchen", 30, "in", "ns", ["Königsgäßchen"]
+            "Königsgäßchen",
+            30,
+            "in",
+            "ns",
+            ["Königsgäßchen"],
+            idna_codec=dns.name.IDNA_2003,
         )
         r2 = dns.rrset.from_text_list(
-            "xn--knigsgsschen-lcb0w", 30, "in", "ns", ["xn--knigsgsschen-lcb0w"]
+            "xn--knigsgsschen-lcb0w",
+            30,
+            "in",
+            "ns",
+            ["xn--knigsgsschen-lcb0w"],
+            idna_codec=dns.name.IDNA_2003,
         )
         self.assertEqual(r1, r2)