]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Add a way to dynamically register an rdata module.
authorBob Halley <halley@dnspython.org>
Tue, 17 Jul 2018 14:02:38 +0000 (07:02 -0700)
committerBob Halley <halley@dnspython.org>
Tue, 17 Jul 2018 14:02:50 +0000 (07:02 -0700)
dns/rdata.py
dns/rdatatype.py
tests/test_rdata.py
tests/ttxt_module.py [new file with mode: 0644]

index 89b78492b6f81dc65755ff5146000ed6e10f504d..6f8a39839c91e52305f9cadb06d249007eef43a5 100644 (file)
@@ -417,3 +417,35 @@ def from_wire(rdclass, rdtype, wire, current, rdlen, origin=None):
     wire = dns.wiredata.maybe_wrap(wire)
     cls = get_rdata_class(rdclass, rdtype)
     return cls.from_wire(rdclass, rdtype, wire, current, rdlen, origin)
+
+
+class RdatatypeExists(dns.exception.DNSException):
+    """DNS rdatatype already exists."""
+    supp_kwargs = set(['rdclass', 'rdtype'])
+    fmt = "The rdata type with class {rdclass} and rdtype {rdtype} " + \
+        "already exists."
+
+
+def register_type(implementation, rdtype, rdtype_text, is_singleton=False,
+                  rdclass=dns.rdataclass.IN):
+    """Dynamically register a module to handle an rdatatype.
+
+    *implementation*, a module implementing the type in the usual dnspython
+    way.
+
+    *rdtype*, an ``int``, the rdatatype to register.
+
+    *rdtype_text*, a ``text``, the textual form of the rdatatype.
+
+    *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e.
+    RRsets of the type can have only one member.)
+
+    *rdclass*, the rdataclass of the type, or ``dns.rdataclass.ANY`` if
+    it applies to all classes.
+    """
+
+    existing_cls = get_rdata_class(rdclass, rdtype)
+    if existing_cls != GenericRdata:
+        raise RdatatypeExists(rdclass=rdclass, rdtype=rdtype)
+    _rdata_modules[(rdclass, rdtype)] = implementation
+    dns.rdatatype.register_type(rdtype, rdtype_text, is_singleton)
index 48d2aa6706f559eb1628228e140e3e508bad2988..6d2535884e8ad37c21b6f88573cd65e2569acb0d 100644 (file)
@@ -266,3 +266,20 @@ def is_singleton(rdtype):
     if rdtype in _singletons:
         return True
     return False
+
+
+def register_type(rdtype, rdtype_text, is_singleton=False):
+    """Dynamically register an rdatatype.
+
+    *rdtype*, an ``int``, the rdatatype to register.
+
+    *rdtype_text*, a ``text``, the textual form of the rdatatype.
+
+    *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e.
+    RRsets of the type can have only one member.)
+    """
+
+    _by_text[rdtype_text] = rdtype
+    _by_value[rdtype] = rdtype_text
+    if is_singleton:
+        _singletons[rdtype] = True
index fbf11b3914fb0a42974ef94c077151eedb937824..b67470e1ab157f8ddf702a01612f8cbf7b7d695f 100644 (file)
@@ -22,6 +22,8 @@ import dns.rdata
 import dns.rdataclass
 import dns.rdatatype
 
+import ttxt_module
+
 class RdataTestCase(unittest.TestCase):
 
     def test_str(self):
@@ -32,5 +34,19 @@ class RdataTestCase(unittest.TestCase):
         rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, u"1.2.3.4")
         self.failUnless(rdata.address == "1.2.3.4")
 
+    def test_module_registration(self):
+        TTXT = 64001
+        dns.rdata.register_type(ttxt_module, TTXT, 'TTXT')
+        rdata = dns.rdata.from_text(dns.rdataclass.IN, TTXT, 'hello world')
+        self.failUnless(rdata.strings == [b'hello', b'world'])
+        self.failUnless(dns.rdatatype.to_text(TTXT) == 'TTXT')
+        self.failUnless(dns.rdatatype.from_text('TTXT') == TTXT)
+
+    def test_module_reregistration(self):
+        def bad():
+            TTXTTWO = dns.rdatatype.TXT
+            dns.rdata.register_type(ttxt_module, TTXTTWO, 'TTXTTWO')
+        self.failUnlessRaises(dns.rdata.RdatatypeExists, bad)
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/ttxt_module.py b/tests/ttxt_module.py
new file mode 100644 (file)
index 0000000..c66131b
--- /dev/null
@@ -0,0 +1,4 @@
+import dns.rdtypes.txtbase
+
+class TTXT(dns.rdtypes.txtbase.TXTBase):
+    """Test TXT-like record"""