BIND 10 trac1245, updated. 18083458382473b414a3fc7f57623d2241f487ef [1245] move all s_ decls to inside the .cc

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Sep 16 00:46:19 UTC 2011


The branch, trac1245 has been updated
       via  18083458382473b414a3fc7f57623d2241f487ef (commit)
       via  fbe4ee1f76237fdd586638ce1ded4c6e5bd0bf1d (commit)
       via  9c53309978b4a4bf684b3abbb853876c5413f875 (commit)
      from  8ee5844e8dc3ec7d99a5890bdc85f54afd8886b6 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 18083458382473b414a3fc7f57623d2241f487ef
Author: Jelte Jansen <jelte at isc.org>
Date:   Fri Sep 16 01:35:40 2011 +0200

    [1245] move all s_ decls to inside the .cc
    
    Added a lot of conversion functions for that

commit fbe4ee1f76237fdd586638ce1ded4c6e5bd0bf1d
Author: Jelte Jansen <jelte at isc.org>
Date:   Thu Sep 15 21:50:02 2011 +0200

    [1245] rename internal object to cppobj for consistency

commit 9c53309978b4a4bf684b3abbb853876c5413f875
Author: Jelte Jansen <jelte at isc.org>
Date:   Thu Sep 15 21:09:15 2011 +0200

    [1245] remove initModule from headers
    
    and move it to an internal namespace
    move the declaration of the functions to pydnspp.cc

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dns/python/edns_python.cc            |   98 +++++++++++-----
 src/lib/dns/python/edns_python.h             |   37 ++++--
 src/lib/dns/python/message_python.cc         |  163 ++++++++++----------------
 src/lib/dns/python/message_python.h          |    7 -
 src/lib/dns/python/messagerenderer_python.cc |   80 +++++++++++---
 src/lib/dns/python/messagerenderer_python.h  |   39 ++++--
 src/lib/dns/python/name_python.cc            |   25 +++-
 src/lib/dns/python/name_python.h             |   18 +---
 src/lib/dns/python/opcode_python.cc          |   50 +++++++--
 src/lib/dns/python/opcode_python.h           |   41 ++++---
 src/lib/dns/python/pydnspp.cc                |   54 +++++----
 src/lib/dns/python/pydnspp_towire.h          |    4 +-
 src/lib/dns/python/question_python.cc        |   84 +++++++-------
 src/lib/dns/python/question_python.h         |   32 ++++-
 src/lib/dns/python/rcode_python.cc           |   48 +++++++-
 src/lib/dns/python/rcode_python.h            |   47 ++++----
 src/lib/dns/python/rdata_python.cc           |   71 +++++++++---
 src/lib/dns/python/rdata_python.h            |   32 ++++-
 src/lib/dns/python/rrclass_python.cc         |   18 ++-
 src/lib/dns/python/rrclass_python.h          |   15 +---
 src/lib/dns/python/rrset_python.cc           |  148 +++++++++--------------
 src/lib/dns/python/rrset_python.h            |   23 ++---
 src/lib/dns/python/rrttl_python.cc           |   67 ++++++++---
 src/lib/dns/python/rrttl_python.h            |   32 ++++-
 src/lib/dns/python/rrtype_python.cc          |   16 ++-
 src/lib/dns/python/rrtype_python.h           |   11 +--
 src/lib/dns/python/tsig_python.cc            |   50 +++++---
 src/lib/dns/python/tsig_python.h             |   26 +++--
 src/lib/dns/python/tsig_rdata_python.cc      |   30 ++++-
 src/lib/dns/python/tsig_rdata_python.h       |   27 +++--
 src/lib/dns/python/tsigerror_python.cc       |   28 +++---
 src/lib/dns/python/tsigerror_python.h        |   10 +--
 src/lib/dns/python/tsigkey_python.cc         |   73 +++++++++---
 src/lib/dns/python/tsigkey_python.h          |   50 ++++++---
 src/lib/dns/python/tsigrecord_python.cc      |   33 +++++-
 src/lib/dns/python/tsigrecord_python.h       |   27 +++--
 36 files changed, 991 insertions(+), 623 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/lib/dns/python/edns_python.cc b/src/lib/dns/python/edns_python.cc
index 7915465..b1073d8 100644
--- a/src/lib/dns/python/edns_python.cc
+++ b/src/lib/dns/python/edns_python.cc
@@ -19,6 +19,7 @@
 #include <dns/edns.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "edns_python.h"
 #include "name_python.h"
@@ -30,12 +31,20 @@
 #include "pydnspp_common.h"
 
 using namespace isc::dns;
-using namespace isc::util;
 using namespace isc::dns::rdata;
 using namespace isc::dns::python;
+using namespace isc::util;
+using namespace isc::util::python;
 
 namespace {
 
+class s_EDNS : public PyObject {
+public:
+    EDNS* cppobj;
+};
+
+typedef CPPPyObjectContainer<s_EDNS, EDNS> EDNSContainer;
+
 // General creation and destruction
 int EDNS_init(s_EDNS* self, PyObject* args);
 void EDNS_destroy(s_EDNS* self);
@@ -116,15 +125,15 @@ createFromRR(const Name& name, const RRClass& rrclass, const RRType& rrtype,
 int
 EDNS_init(s_EDNS* self, PyObject* args) {
     uint8_t version = EDNS::SUPPORTED_VERSION;
-    const s_Name* name;
-    const s_RRClass* rrclass;
-    const s_RRType* rrtype;
-    const s_RRTTL* rrttl;
-    const s_Rdata* rdata;
+    const PyObject* name;
+    const PyObject* rrclass;
+    const PyObject* rrtype;
+    const PyObject* rrttl;
+    const PyObject* rdata;
 
     if (PyArg_ParseTuple(args, "|b", &version)) {
         try {
-            self->edns = new EDNS(version);
+            self->cppobj = new EDNS(version);
         } catch (const isc::InvalidParameter& ex) {
             PyErr_SetString(po_InvalidParameter, ex.what());
             return (-1);
@@ -140,10 +149,12 @@ EDNS_init(s_EDNS* self, PyObject* args) {
         // in this context so that we can share the try-catch logic with
         // EDNS_createFromRR() (see below).
         uint8_t extended_rcode;
-        self->edns = createFromRR(*name->cppobj, *rrclass->cppobj,
-                                  *rrtype->cppobj, *rrttl->rrttl,
-                                  *rdata->rdata, extended_rcode);
-        return (self->edns != NULL ? 0 : -1);
+        self->cppobj = createFromRR(PyName_ToName(name),
+                                    PyRRClass_ToRRClass(rrclass),
+                                    PyRRType_ToRRType(rrtype),
+                                    PyRRTTL_ToRRTTL(rrttl),
+                                    PyRdata_ToRdata(rdata), extended_rcode);
+        return (self->cppobj != NULL ? 0 : -1);
     }
 
     PyErr_Clear();
@@ -154,15 +165,15 @@ EDNS_init(s_EDNS* self, PyObject* args) {
 
 void
 EDNS_destroy(s_EDNS* const self) {
-    delete self->edns;
-    self->edns = NULL;
+    delete self->cppobj;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
 PyObject*
 EDNS_toText(const s_EDNS* const self) {
     // Py_BuildValue makes python objects from native data
-    return (Py_BuildValue("s", self->edns->toText().c_str()));
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
 }
 
 PyObject*
@@ -177,14 +188,14 @@ PyObject*
 EDNS_toWire(const s_EDNS* const self, PyObject* args) {
     PyObject* bytes;
     uint8_t extended_rcode;
-    s_MessageRenderer* renderer;
+    PyObject* renderer;
 
     if (PyArg_ParseTuple(args, "Ob", &bytes, &extended_rcode) &&
         PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
 
         OutputBuffer buffer(0);
-        self->edns->toWire(buffer, extended_rcode);
+        self->cppobj->toWire(buffer, extended_rcode);
         PyObject* rd_bytes = PyBytes_FromStringAndSize(
             static_cast<const char*>(buffer.getData()), buffer.getLength());
         PyObject* result = PySequence_InPlaceConcat(bytes_o, rd_bytes);
@@ -194,8 +205,8 @@ EDNS_toWire(const s_EDNS* const self, PyObject* args) {
         return (result);
     } else if (PyArg_ParseTuple(args, "O!b", &messagerenderer_type,
                                 &renderer, &extended_rcode)) {
-        const unsigned int n = self->edns->toWire(*renderer->messagerenderer,
-                                                  extended_rcode);
+        const unsigned int n = self->cppobj->toWire(
+            PyMessageRenderer_ToMessageRenderer(renderer), extended_rcode);
 
         return (Py_BuildValue("I", n));
     }
@@ -206,12 +217,12 @@ EDNS_toWire(const s_EDNS* const self, PyObject* args) {
 
 PyObject*
 EDNS_getVersion(const s_EDNS* const self) {
-    return (Py_BuildValue("B", self->edns->getVersion()));
+    return (Py_BuildValue("B", self->cppobj->getVersion()));
 }
 
 PyObject*
 EDNS_getDNSSECAwareness(const s_EDNS* const self) {
-    if (self->edns->getDNSSECAwareness()) {
+    if (self->cppobj->getDNSSECAwareness()) {
         Py_RETURN_TRUE;
     } else {
         Py_RETURN_FALSE;
@@ -224,13 +235,13 @@ EDNS_setDNSSECAwareness(s_EDNS* self, PyObject* args) {
     if (!PyArg_ParseTuple(args, "O!", &PyBool_Type, &b)) {
         return (NULL);
     }
-    self->edns->setDNSSECAwareness(b == Py_True);
+    self->cppobj->setDNSSECAwareness(b == Py_True);
     Py_RETURN_NONE;
 }
 
 PyObject*
 EDNS_getUDPSize(const s_EDNS* const self) {
-    return (Py_BuildValue("I", self->edns->getUDPSize()));
+    return (Py_BuildValue("I", self->cppobj->getUDPSize()));
 }
 
 PyObject*
@@ -247,17 +258,17 @@ EDNS_setUDPSize(s_EDNS* self, PyObject* args) {
                         "UDP size is not an unsigned 16-bit integer");
         return (NULL);
     }
-    self->edns->setUDPSize(size);
+    self->cppobj->setUDPSize(size);
     Py_RETURN_NONE;
 }
 
 PyObject*
 EDNS_createFromRR(const s_EDNS* null_self, PyObject* args) {
-    const s_Name* name;
-    const s_RRClass* rrclass;
-    const s_RRType* rrtype;
-    const s_RRTTL* rrttl;
-    const s_Rdata* rdata;
+    const PyObject* name;
+    const PyObject* rrclass;
+    const PyObject* rrtype;
+    const PyObject* rrttl;
+    const PyObject* rdata;
     s_EDNS* edns_obj = NULL;
 
     assert(null_self == NULL);
@@ -271,10 +282,13 @@ EDNS_createFromRR(const s_EDNS* null_self, PyObject* args) {
             return (NULL);
         }
 
-        edns_obj->edns = createFromRR(*name->cppobj, *rrclass->cppobj,
-                                      *rrtype->cppobj, *rrttl->rrttl,
-                                      *rdata->rdata, extended_rcode);
-        if (edns_obj->edns != NULL) {
+        edns_obj->cppobj = createFromRR(PyName_ToName(name),
+                                        PyRRClass_ToRRClass(rrclass),
+                                        PyRRType_ToRRType(rrtype),
+                                        PyRRTTL_ToRRTTL(rrttl),
+                                        PyRdata_ToRdata(rdata),
+                                        extended_rcode);
+        if (edns_obj->cppobj != NULL) {
             PyObject* extrcode_obj = Py_BuildValue("B", extended_rcode);
             return (Py_BuildValue("OO", edns_obj, extrcode_obj));
         }
@@ -349,6 +363,7 @@ PyTypeObject edns_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool
 initModulePart_EDNS(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -366,6 +381,25 @@ initModulePart_EDNS(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+PyObject*
+createEDNSObject(const EDNS& source) {
+    EDNSContainer container = PyObject_New(s_EDNS, &edns_type);
+    container.set(new EDNS(source));
+    return (container.release());
+}
+
+bool
+PyEDNS_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &edns_type));
+}
+
+const EDNS&
+PyEDNS_ToEDNS(const PyObject* edns_obj) {
+    const s_EDNS* edns = static_cast<const s_EDNS*>(edns_obj);
+    return (*edns->cppobj);
+}
 
 } // end namespace python
 } // end namespace dns
diff --git a/src/lib/dns/python/edns_python.h b/src/lib/dns/python/edns_python.h
index 94b0820..a6d3c38 100644
--- a/src/lib/dns/python/edns_python.h
+++ b/src/lib/dns/python/edns_python.h
@@ -23,19 +23,34 @@ namespace isc {
 namespace dns {
 namespace python {
 
-//
-// Declaration of the custom exceptions
-// Initialization and addition of these go in the module init at the
-// end
-//
-class s_EDNS : public PyObject {
-public:
-    EDNS* edns;
-};
-
 extern PyTypeObject edns_type;
 
-bool initModulePart_EDNS(PyObject* mod);
+/// This is a simple shortcut to create a python EDNS object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createEDNSObject(const EDNS& source);
+
+/// \brief Checks if the given python object is a EDNS object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type EDNS, false otherwise
+bool PyEDNS_Check(PyObject* obj);
+
+/// \brief Returns a reference to the EDNS object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type EDNS; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyEDNS_Check()
+///
+/// \note This is not a copy; if the EDNS is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param edns_obj The edns object to convert
+const EDNS& PyEDNS_ToEDNS(const PyObject* edns_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/message_python.cc b/src/lib/dns/python/message_python.cc
index cd945fb..0ac1aab 100644
--- a/src/lib/dns/python/message_python.cc
+++ b/src/lib/dns/python/message_python.cc
@@ -40,6 +40,10 @@ using namespace isc::dns::python;
 using namespace isc::util;
 
 namespace {
+class s_Message : public PyObject {
+public:
+    isc::dns::Message* cppobj;
+};
 
 int Message_init(s_Message* self, PyObject* args);
 void Message_destroy(s_Message* self);
@@ -171,10 +175,10 @@ Message_init(s_Message* self, PyObject* args) {
     if (PyArg_ParseTuple(args, "i", &i)) {
         PyErr_Clear();
         if (i == Message::PARSE) {
-            self->message = new Message(Message::PARSE);
+            self->cppobj = new Message(Message::PARSE);
             return (0);
         } else if (i == Message::RENDER) {
-            self->message = new Message(Message::RENDER);
+            self->cppobj = new Message(Message::RENDER);
             return (0);
         } else {
             PyErr_SetString(PyExc_TypeError, "Message mode must be Message.PARSE or Message.RENDER");
@@ -189,8 +193,8 @@ Message_init(s_Message* self, PyObject* args) {
 
 void
 Message_destroy(s_Message* self) {
-    delete self->message;
-    self->message = NULL;
+    delete self->cppobj;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
@@ -204,7 +208,7 @@ Message_getHeaderFlag(s_Message* self, PyObject* args) {
         return (NULL);
     }
 
-    if (self->message->getHeaderFlag(
+    if (self->cppobj->getHeaderFlag(
             static_cast<Message::HeaderFlag>(messageflag))) {
         Py_RETURN_TRUE;
     } else {
@@ -229,7 +233,7 @@ Message_setHeaderFlag(s_Message* self, PyObject* args) {
     }
 
     try {
-        self->message->setHeaderFlag(
+        self->cppobj->setHeaderFlag(
             static_cast<Message::HeaderFlag>(messageflag), on == Py_True);
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
@@ -245,7 +249,7 @@ Message_setHeaderFlag(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_getQid(s_Message* self) {
-    return (Py_BuildValue("I", self->message->getQid()));
+    return (Py_BuildValue("I", self->cppobj->getQid()));
 }
 
 PyObject*
@@ -264,7 +268,7 @@ Message_setQid(s_Message* self, PyObject* args) {
     }
 
     try {
-        self->message->setQid(id);
+        self->cppobj->setQid(id);
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -274,35 +278,25 @@ Message_setQid(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_getRcode(s_Message* self) {
-    s_Rcode* rcode;
-
-    rcode = static_cast<s_Rcode*>(rcode_type.tp_alloc(&rcode_type, 0));
-    if (rcode != NULL) {
-        rcode->cppobj = NULL;
-        try {
-            rcode->cppobj = new Rcode(self->message->getRcode());
-        } catch (const InvalidMessageOperation& imo) {
-            PyErr_SetString(po_InvalidMessageOperation, imo.what());
-        } catch (...) {
-            PyErr_SetString(po_IscException, "Unexpected exception");
-        }
-        if (rcode->cppobj == NULL) {
-            Py_DECREF(rcode);
-            return (NULL);
-        }
+    try {
+        return (createRcodeObject(self->cppobj->getRcode()));
+    } catch (const InvalidMessageOperation& imo) {
+        PyErr_SetString(po_InvalidMessageOperation, imo.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(po_IscException, "Unexpected exception");
+        return (NULL);
     }
-
-    return (rcode);
 }
 
 PyObject*
 Message_setRcode(s_Message* self, PyObject* args) {
-    s_Rcode* rcode;
+    PyObject* rcode;
     if (!PyArg_ParseTuple(args, "O!", &rcode_type, &rcode)) {
         return (NULL);
     }
     try {
-        self->message->setRcode(*rcode->cppobj);
+        self->cppobj->setRcode(PyRcode_ToRcode(rcode));
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -312,35 +306,25 @@ Message_setRcode(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_getOpcode(s_Message* self) {
-    s_Opcode* opcode;
-
-    opcode = static_cast<s_Opcode*>(opcode_type.tp_alloc(&opcode_type, 0));
-    if (opcode != NULL) {
-        opcode->opcode = NULL;
-        try {
-            opcode->opcode = new Opcode(self->message->getOpcode());
-        } catch (const InvalidMessageOperation& imo) {
-            PyErr_SetString(po_InvalidMessageOperation, imo.what());
-        } catch (...) {
-            PyErr_SetString(po_IscException, "Unexpected exception");
-        }
-        if (opcode->opcode == NULL) {
-            Py_DECREF(opcode);
-            return (NULL);
-        }
+    try {
+        return (createOpcodeObject(self->cppobj->getOpcode()));
+    } catch (const InvalidMessageOperation& imo) {
+        PyErr_SetString(po_InvalidMessageOperation, imo.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(po_IscException, "Unexpected exception");
+        return (NULL);
     }
-
-    return (opcode);
 }
 
 PyObject*
 Message_setOpcode(s_Message* self, PyObject* args) {
-    s_Opcode* opcode;
+    PyObject* opcode;
     if (!PyArg_ParseTuple(args, "O!", &opcode_type, &opcode)) {
         return (NULL);
     }
     try {
-        self->message->setOpcode(*opcode->opcode);
+        self->cppobj->setOpcode(PyOpcode_ToOpcode(opcode));
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -350,32 +334,21 @@ Message_setOpcode(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_getEDNS(s_Message* self) {
-    s_EDNS* edns;
-    EDNS* edns_body;
-    ConstEDNSPtr src = self->message->getEDNS();
-
+    ConstEDNSPtr src = self->cppobj->getEDNS();
     if (!src) {
         Py_RETURN_NONE;
     }
-    if ((edns_body = new(nothrow) EDNS(*src)) == NULL) {
-        return (PyErr_NoMemory());
-    }
-    edns = static_cast<s_EDNS*>(opcode_type.tp_alloc(&edns_type, 0));
-    if (edns != NULL) {
-        edns->edns = edns_body;
-    }
-
-    return (edns);
+    return (createEDNSObject(*src));
 }
 
 PyObject*
 Message_setEDNS(s_Message* self, PyObject* args) {
-    s_EDNS* edns;
+    PyObject* edns;
     if (!PyArg_ParseTuple(args, "O!", &edns_type, &edns)) {
         return (NULL);
     }
     try {
-        self->message->setEDNS(EDNSPtr(new EDNS(*edns->edns)));
+        self->cppobj->setEDNS(EDNSPtr(new EDNS(PyEDNS_ToEDNS(edns))));
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -386,7 +359,7 @@ Message_setEDNS(s_Message* self, PyObject* args) {
 PyObject*
 Message_getTSIGRecord(s_Message* self) {
     try {
-        const TSIGRecord* tsig_record = self->message->getTSIGRecord();
+        const TSIGRecord* tsig_record = self->cppobj->getTSIGRecord();
 
         if (tsig_record == NULL) {
             Py_RETURN_NONE;
@@ -416,7 +389,7 @@ Message_getRRCount(s_Message* self, PyObject* args) {
         return (NULL);
     }
     try {
-        return (Py_BuildValue("I", self->message->getRRCount(
+        return (Py_BuildValue("I", self->cppobj->getRRCount(
                                   static_cast<Message::Section>(section))));
     } catch (const isc::OutOfRange& ex) {
         PyErr_SetString(PyExc_OverflowError, ex.what());
@@ -429,8 +402,8 @@ PyObject*
 Message_getQuestion(s_Message* self) {
     QuestionIterator qi, qi_end;
     try {
-        qi = self->message->beginQuestion();
-        qi_end = self->message->endQuestion();
+        qi = self->cppobj->beginQuestion();
+        qi_end = self->cppobj->endQuestion();
     } catch (const InvalidMessageSection& ex) {
         PyErr_SetString(po_InvalidMessageSection, ex.what());
         return (NULL);
@@ -446,20 +419,10 @@ Message_getQuestion(s_Message* self) {
     }
 
     for (; qi != qi_end; ++qi) {
-        s_Question *question = static_cast<s_Question*>(
-            question_type.tp_alloc(&question_type, 0));
-        if (question == NULL) {
-            Py_DECREF(question);
+        if (PyList_Append(list, createQuestionObject(**qi)) == -1) {
             Py_DECREF(list);
             return (NULL);
         }
-        question->question = *qi;
-        if (PyList_Append(list, question) == -1) {
-            Py_DECREF(question);
-            Py_DECREF(list);
-            return (NULL);
-        }
-        Py_DECREF(question);
     }
     return (list);
 }
@@ -475,9 +438,9 @@ Message_getSection(s_Message* self, PyObject* args) {
     }
     RRsetIterator rrsi, rrsi_end;
     try {
-        rrsi = self->message->beginSection(
+        rrsi = self->cppobj->beginSection(
             static_cast<Message::Section>(section));
-        rrsi_end = self->message->endSection(
+        rrsi_end = self->cppobj->endSection(
             static_cast<Message::Section>(section));
     } catch (const isc::OutOfRange& ex) {
         PyErr_SetString(PyExc_OverflowError, ex.what());
@@ -496,14 +459,7 @@ Message_getSection(s_Message* self, PyObject* args) {
         return (NULL);
     }
     for (; rrsi != rrsi_end; ++rrsi) {
-        s_RRset *rrset = static_cast<s_RRset*>(
-            rrset_type.tp_alloc(&rrset_type, 0));
-        if (rrset == NULL) {
-                Py_DECREF(rrset);
-                Py_DECREF(list);
-                return (NULL);
-        }
-        rrset->rrset = *rrsi;
+        PyObject* rrset = createRRsetObject(**rrsi);
         if (PyList_Append(list, rrset) == -1) {
                 Py_DECREF(rrset);
                 Py_DECREF(list);
@@ -523,13 +479,13 @@ Message_getSection(s_Message* self, PyObject* args) {
 //static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
 PyObject*
 Message_addQuestion(s_Message* self, PyObject* args) {
-    s_Question *question;
+    PyObject* question;
 
     if (!PyArg_ParseTuple(args, "O!", &question_type, &question)) {
         return (NULL);
     }
 
-    self->message->addQuestion(question->question);
+    self->cppobj->addQuestion(PyQuestion_ToQuestion(question));
 
     Py_RETURN_NONE;
 }
@@ -538,15 +494,15 @@ PyObject*
 Message_addRRset(s_Message* self, PyObject* args) {
     PyObject *sign = Py_False;
     int section;
-    s_RRset* rrset;
+    PyObject* rrset;
     if (!PyArg_ParseTuple(args, "iO!|O!", &section, &rrset_type, &rrset,
                           &PyBool_Type, &sign)) {
         return (NULL);
     }
 
     try {
-        self->message->addRRset(static_cast<Message::Section>(section),
-                                rrset->rrset, sign == Py_True);
+        self->cppobj->addRRset(static_cast<Message::Section>(section),
+                               PyRRset_ToRRsetPtr(rrset), sign == Py_True);
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -567,10 +523,10 @@ Message_clear(s_Message* self, PyObject* args) {
     if (PyArg_ParseTuple(args, "i", &i)) {
         PyErr_Clear();
         if (i == Message::PARSE) {
-            self->message->clear(Message::PARSE);
+            self->cppobj->clear(Message::PARSE);
             Py_RETURN_NONE;
         } else if (i == Message::RENDER) {
-            self->message->clear(Message::RENDER);
+            self->cppobj->clear(Message::RENDER);
             Py_RETURN_NONE;
         } else {
             PyErr_SetString(PyExc_TypeError,
@@ -584,7 +540,7 @@ Message_clear(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_makeResponse(s_Message* self) {
-    self->message->makeResponse();
+    self->cppobj->makeResponse();
     Py_RETURN_NONE;
 }
 
@@ -592,7 +548,7 @@ PyObject*
 Message_toText(s_Message* self) {
     // Py_BuildValue makes python objects from native data
     try {
-        return (Py_BuildValue("s", self->message->toText().c_str()));
+        return (Py_BuildValue("s", self->cppobj->toText().c_str()));
     } catch (const InvalidMessageOperation& imo) {
         PyErr_Clear();
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -613,16 +569,17 @@ Message_str(PyObject* self) {
 
 PyObject*
 Message_toWire(s_Message* self, PyObject* args) {
-    s_MessageRenderer* mr;
-    s_TSIGContext* tsig_ctx = NULL;
+    PyObject* mr;
+    PyObject* tsig_ctx = NULL;
 
     if (PyArg_ParseTuple(args, "O!|O!", &messagerenderer_type, &mr,
                          &tsigcontext_type, &tsig_ctx)) {
         try {
             if (tsig_ctx == NULL) {
-                self->message->toWire(*mr->messagerenderer);
+                self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
             } else {
-                self->message->toWire(*mr->messagerenderer, *tsig_ctx->cppobj);
+                self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr),
+                                     PyTSIGContext_ToTSIGContext(tsig_ctx));
             }
             // If we return NULL it is seen as an error, so use this for
             // None returns
@@ -663,7 +620,7 @@ Message_fromWire(s_Message* self, PyObject* args) {
 
     InputBuffer inbuf(b, len);
     try {
-        self->message->fromWire(inbuf);
+        self->cppobj->fromWire(inbuf);
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -750,6 +707,7 @@ PyTypeObject message_type = {
 };
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_Message(PyObject* mod) {
     if (PyType_Ready(&message_type) < 0) {
@@ -816,6 +774,7 @@ initModulePart_Message(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 } // end python namespace
 } // end dns namespace
diff --git a/src/lib/dns/python/message_python.h b/src/lib/dns/python/message_python.h
index 325eb8e..be1adb9 100644
--- a/src/lib/dns/python/message_python.h
+++ b/src/lib/dns/python/message_python.h
@@ -33,15 +33,8 @@ extern PyObject* po_InvalidMessageSection;
 extern PyObject* po_InvalidMessageOperation;
 extern PyObject* po_InvalidMessageUDPSize;
 
-class s_Message : public PyObject {
-public:
-    isc::dns::Message* message;
-};
-
 extern PyTypeObject message_type;
 
-bool initModulePart_Message(PyObject* mod);
-
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/messagerenderer_python.cc b/src/lib/dns/python/messagerenderer_python.cc
index 3aa2dee..2c475d8 100644
--- a/src/lib/dns/python/messagerenderer_python.cc
+++ b/src/lib/dns/python/messagerenderer_python.cc
@@ -17,6 +17,7 @@
 #include <util/buffer.h>
 
 #include <dns/messagerenderer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "pydnspp_common.h"
 #include "messagerenderer_python.h"
@@ -24,8 +25,21 @@
 using namespace isc::dns;
 using namespace isc::dns::python;
 using namespace isc::util;
+using namespace isc::util::python;
 
 namespace {
+// The s_* Class simply covers one instantiation of the object.
+//
+// since we don't use *Buffer in the python version (but work with
+// the already existing bytearray type where we use these custom buffers
+// in C++, we need to keep track of one here.
+class s_MessageRenderer : public PyObject {
+public:
+    s_MessageRenderer();
+    isc::util::OutputBuffer* outputbuffer;
+    MessageRenderer* cppobj;
+};
+
 int MessageRenderer_init(s_MessageRenderer* self);
 void MessageRenderer_destroy(s_MessageRenderer* self);
 
@@ -65,15 +79,15 @@ PyMethodDef MessageRenderer_methods[] = {
 int
 MessageRenderer_init(s_MessageRenderer* self) {
     self->outputbuffer = new OutputBuffer(4096);
-    self->messagerenderer = new MessageRenderer(*self->outputbuffer);
+    self->cppobj = new MessageRenderer(*self->outputbuffer);
     return (0);
 }
 
 void
 MessageRenderer_destroy(s_MessageRenderer* self) {
-    delete self->messagerenderer;
+    delete self->cppobj;
     delete self->outputbuffer;
-    self->messagerenderer = NULL;
+    self->cppobj = NULL;
     self->outputbuffer = NULL;
     Py_TYPE(self)->tp_free(self);
 }
@@ -81,18 +95,18 @@ MessageRenderer_destroy(s_MessageRenderer* self) {
 PyObject*
 MessageRenderer_getData(s_MessageRenderer* self) {
     return (Py_BuildValue("y#",
-                         self->messagerenderer->getData(),
-                          self->messagerenderer->getLength()));
+                          self->cppobj->getData(),
+                          self->cppobj->getLength()));
 }
 
 PyObject*
 MessageRenderer_getLength(s_MessageRenderer* self) {
-    return (Py_BuildValue("I", self->messagerenderer->getLength()));
+    return (Py_BuildValue("I", self->cppobj->getLength()));
 }
 
 PyObject*
 MessageRenderer_isTruncated(s_MessageRenderer* self) {
-    if (self->messagerenderer->isTruncated()) {
+    if (self->cppobj->isTruncated()) {
         Py_RETURN_TRUE;
     } else {
         Py_RETURN_FALSE;
@@ -101,17 +115,17 @@ MessageRenderer_isTruncated(s_MessageRenderer* self) {
 
 PyObject*
 MessageRenderer_getLengthLimit(s_MessageRenderer* self) {
-    return (Py_BuildValue("I", self->messagerenderer->getLengthLimit()));
+    return (Py_BuildValue("I", self->cppobj->getLengthLimit()));
 }
 
 PyObject*
 MessageRenderer_getCompressMode(s_MessageRenderer* self) {
-    return (Py_BuildValue("I", self->messagerenderer->getCompressMode()));
+    return (Py_BuildValue("I", self->cppobj->getCompressMode()));
 }
 
 PyObject*
 MessageRenderer_setTruncated(s_MessageRenderer* self) {
-    self->messagerenderer->setTruncated();
+    self->cppobj->setTruncated();
     Py_RETURN_NONE;
 }
 
@@ -131,7 +145,7 @@ MessageRenderer_setLengthLimit(s_MessageRenderer* self,
                         "MessageRenderer length limit out of range");
         return (NULL);
     }
-    self->messagerenderer->setLengthLimit(lengthlimit);
+    self->cppobj->setLengthLimit(lengthlimit);
     Py_RETURN_NONE;
 }
 
@@ -145,12 +159,12 @@ MessageRenderer_setCompressMode(s_MessageRenderer* self,
     }
 
     if (mode == MessageRenderer::CASE_INSENSITIVE) {
-        self->messagerenderer->setCompressMode(MessageRenderer::CASE_INSENSITIVE);
+        self->cppobj->setCompressMode(MessageRenderer::CASE_INSENSITIVE);
         // If we return NULL it is seen as an error, so use this for
         // None returns, it also applies to CASE_SENSITIVE.
         Py_RETURN_NONE;
     } else if (mode == MessageRenderer::CASE_SENSITIVE) {
-        self->messagerenderer->setCompressMode(MessageRenderer::CASE_SENSITIVE);
+        self->cppobj->setCompressMode(MessageRenderer::CASE_SENSITIVE);
         Py_RETURN_NONE;
     } else {
         PyErr_SetString(PyExc_TypeError,
@@ -162,7 +176,7 @@ MessageRenderer_setCompressMode(s_MessageRenderer* self,
 
 PyObject*
 MessageRenderer_clear(s_MessageRenderer* self) {
-    self->messagerenderer->clear();
+    self->cppobj->clear();
     Py_RETURN_NONE;
 }
 } // end of unnamed namespace
@@ -225,6 +239,7 @@ PyTypeObject messagerenderer_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool initModulePart_MessageRenderer(PyObject* mod) {
     if (PyType_Ready(&messagerenderer_type) < 0) {
         return (false);
@@ -241,6 +256,43 @@ bool initModulePart_MessageRenderer(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+PyObject*
+createMessageRendererObject(const MessageRenderer& source) {
+    // should we copy? can we?
+    // copy the existing buffer into a new one, then create a new renderer with
+    // that buffer
+    s_MessageRenderer* mr = static_cast<s_MessageRenderer*>(
+        messagerenderer_type.tp_alloc(&messagerenderer_type, 0));
+    if (mr == NULL) {
+        isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+                  "probably due to short memory");
+    }
+    try {
+        mr->outputbuffer = new OutputBuffer(4096);
+        mr->outputbuffer->writeData(source.getData(), source.getLength());
+        mr->cppobj = new MessageRenderer(*mr->outputbuffer);
+
+        return (mr);
+    } catch (const std::bad_alloc&) {
+        isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+                  "probably due to short memory");
+    }
+}
+
+bool
+PyMessageRenderer_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &messagerenderer_type));
+}
+
+MessageRenderer&
+PyMessageRenderer_ToMessageRenderer(PyObject* messagerenderer_obj) {
+    s_MessageRenderer* messagerenderer = static_cast<s_MessageRenderer*>(messagerenderer_obj);
+    return (*messagerenderer->cppobj);
+}
+
+
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/messagerenderer_python.h b/src/lib/dns/python/messagerenderer_python.h
index cc28e43..2f51853 100644
--- a/src/lib/dns/python/messagerenderer_python.h
+++ b/src/lib/dns/python/messagerenderer_python.h
@@ -24,21 +24,34 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object.
-//
-// since we don't use *Buffer in the python version (but work with
-// the already existing bytearray type where we use these custom buffers
-// in C++, we need to keep track of one here.
-class s_MessageRenderer : public PyObject {
-public:
-    s_MessageRenderer();
-    isc::util::OutputBuffer* outputbuffer;
-    MessageRenderer* messagerenderer;
-};
-
 extern PyTypeObject messagerenderer_type;
 
-bool initModulePart_MessageRenderer(PyObject* mod);
+/// This is a simple shortcut to create a python MessageRenderer object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createMessageRendererObject(const MessageRenderer& source);
+
+/// \brief Checks if the given python object is a MessageRenderer object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type MessageRenderer, false otherwise
+bool PyMessageRenderer_Check(PyObject* obj);
+
+/// \brief Returns a reference to the MessageRenderer object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type MessageRenderer; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyMessageRenderer_Check()
+///
+/// \note This is not a copy; if the MessageRenderer is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param messagerenderer_obj The messagerenderer object to convert
+MessageRenderer& PyMessageRenderer_ToMessageRenderer(PyObject* messagerenderer_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/name_python.cc b/src/lib/dns/python/name_python.cc
index 2546f6a..40c7673 100644
--- a/src/lib/dns/python/name_python.cc
+++ b/src/lib/dns/python/name_python.cc
@@ -31,6 +31,19 @@ using namespace isc::util;
 using namespace isc::util::python;
 
 namespace {
+// The s_* Class simply covers one instantiation of the object.
+class s_NameComparisonResult : public PyObject {
+public:
+    s_NameComparisonResult() : cppobj(NULL) {}
+    NameComparisonResult* cppobj;
+};
+
+class s_Name : public PyObject {
+public:
+    s_Name() : cppobj(NULL), position(0) {}
+    Name* cppobj;
+    size_t position;
+};
 
 int NameComparisonResult_init(s_NameComparisonResult*, PyObject*);
 void NameComparisonResult_destroy(s_NameComparisonResult* self);
@@ -282,7 +295,7 @@ Name_str(PyObject* self) {
 PyObject*
 Name_toWire(s_Name* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -296,7 +309,7 @@ Name_toWire(s_Name* self, PyObject* args) {
         Py_DECREF(name_bytes);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->messagerenderer);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -624,6 +637,7 @@ PyTypeObject name_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool
 initModulePart_Name(PyObject* mod) {
     // Add the classes to the module
@@ -704,6 +718,7 @@ initModulePart_Name(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 PyObject*
 createNameObject(const Name& source) {
@@ -717,9 +732,9 @@ PyName_Check(PyObject* obj) {
     return (PyObject_TypeCheck(obj, &name_type));
 }
 
-Name&
-PyName_ToName(PyObject* name_obj) {
-    s_Name* name = static_cast<s_Name*>(name_obj);
+const Name&
+PyName_ToName(const PyObject* name_obj) {
+    const s_Name* name = static_cast<const s_Name*>(name_obj);
     return (*name->cppobj);
 }
 
diff --git a/src/lib/dns/python/name_python.h b/src/lib/dns/python/name_python.h
index 4a4b611..3667c35 100644
--- a/src/lib/dns/python/name_python.h
+++ b/src/lib/dns/python/name_python.h
@@ -44,25 +44,9 @@ extern PyObject* po_DNSMessageFORMERR;
 //
 extern PyObject* po_NameRelation;
 
-// The s_* Class simply covers one instantiation of the object.
-class s_NameComparisonResult : public PyObject {
-public:
-    s_NameComparisonResult() : cppobj(NULL) {}
-    NameComparisonResult* cppobj;
-};
-
-class s_Name : public PyObject {
-public:
-    s_Name() : cppobj(NULL), position(0) {}
-    Name* cppobj;
-    size_t position;
-};
-
 extern PyTypeObject name_comparison_result_type;
 extern PyTypeObject name_type;
 
-bool initModulePart_Name(PyObject* mod);
-
 /// This is A simple shortcut to create a python Name object (in the
 /// form of a pointer to PyObject) with minimal exception safety.
 /// On success, it returns a valid pointer to PyObject with a reference
@@ -88,7 +72,7 @@ bool PyName_Check(PyObject* obj);
 /// may be destroyed, the caller must copy it itself.
 ///
 /// \param name_obj The name object to convert
-Name& PyName_ToName(PyObject* name_obj);
+const Name& PyName_ToName(const PyObject* name_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/opcode_python.cc b/src/lib/dns/python/opcode_python.cc
index 14e2056..1547457 100644
--- a/src/lib/dns/python/opcode_python.cc
+++ b/src/lib/dns/python/opcode_python.cc
@@ -15,6 +15,7 @@
 #include <Python.h>
 
 #include <dns/opcode.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "pydnspp_common.h"
 #include "opcode_python.h"
@@ -23,9 +24,19 @@
 using namespace isc::dns;
 using namespace isc::dns::python;
 using namespace isc::util;
+using namespace isc::util::python;
 
 namespace {
 
+class s_Opcode : public PyObject {
+public:
+    s_Opcode() : cppobj(NULL), static_code(false) {}
+    const isc::dns::Opcode* cppobj;
+    bool static_code;
+};
+
+typedef CPPPyObjectContainer<s_Opcode, Opcode> OpcodeContainer;
+
 int Opcode_init(s_Opcode* const self, PyObject* args);
 void Opcode_destroy(s_Opcode* const self);
 
@@ -97,7 +108,7 @@ Opcode_init(s_Opcode* const self, PyObject* args) {
     uint8_t code = 0;
     if (PyArg_ParseTuple(args, "b", &code)) {
         try {
-            self->opcode = new Opcode(code);
+            self->cppobj = new Opcode(code);
             self->static_code = false;
         } catch (const isc::OutOfRange& ex) {
             PyErr_SetString(PyExc_OverflowError, ex.what());
@@ -118,22 +129,22 @@ Opcode_init(s_Opcode* const self, PyObject* args) {
 void
 Opcode_destroy(s_Opcode* const self) {
     // Depending on whether we created the rcode or are referring
-    // to a global static one, we do or do not delete self->opcode here
+    // to a global static one, we do or do not delete self->cppobj here
     if (!self->static_code) {
-        delete self->opcode;
+        delete self->cppobj;
     }
-    self->opcode = NULL;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
 PyObject*
 Opcode_getCode(const s_Opcode* const self) {
-    return (Py_BuildValue("I", self->opcode->getCode()));
+    return (Py_BuildValue("I", self->cppobj->getCode()));
 }
 
 PyObject*
 Opcode_toText(const s_Opcode* const self) {
-    return (Py_BuildValue("s", self->opcode->toText().c_str()));
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
 }
 
 PyObject*
@@ -148,7 +159,7 @@ PyObject*
 Opcode_createStatic(const Opcode& opcode) {
     s_Opcode* ret = PyObject_New(s_Opcode, &opcode_type);
     if (ret != NULL) {
-        ret->opcode = &opcode;
+        ret->cppobj = &opcode;
         ret->static_code = true;
     }
     return (ret);
@@ -255,10 +266,10 @@ Opcode_richcmp(const s_Opcode* const self, const s_Opcode* const other,
         PyErr_SetString(PyExc_TypeError, "Unorderable type; Opcode");
         return (NULL);
     case Py_EQ:
-        c = (*self->opcode == *other->opcode);
+        c = (*self->cppobj == *other->cppobj);
         break;
     case Py_NE:
-        c = (*self->opcode != *other->opcode);
+        c = (*self->cppobj != *other->cppobj);
         break;
     case Py_GT:
         PyErr_SetString(PyExc_TypeError, "Unorderable type; Opcode");
@@ -330,6 +341,7 @@ PyTypeObject opcode_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool
 initModulePart_Opcode(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -380,6 +392,26 @@ initModulePart_Opcode(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+
+PyObject*
+createOpcodeObject(const Opcode& source) {
+    OpcodeContainer container = PyObject_New(s_Opcode, &opcode_type);
+    container.set(new Opcode(source));
+    return (container.release());
+}
+
+bool
+PyOpcode_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &opcode_type));
+}
+
+const Opcode&
+PyOpcode_ToOpcode(const PyObject* opcode_obj) {
+    const s_Opcode* opcode = static_cast<const s_Opcode*>(opcode_obj);
+    return (*opcode->cppobj);
+}
 
 } // end python namespace
 } // end dns namespace
diff --git a/src/lib/dns/python/opcode_python.h b/src/lib/dns/python/opcode_python.h
index 79860e4..04ee7e7 100644
--- a/src/lib/dns/python/opcode_python.h
+++ b/src/lib/dns/python/opcode_python.h
@@ -23,23 +23,34 @@ namespace isc {
 namespace dns {
 namespace python {
 
-//
-// Declaration of the custom exceptions
-// Initialization and addition of these go in the module init at the
-// end
-//
-
-class s_Opcode : public PyObject {
-public:
-    s_Opcode() : opcode(NULL), static_code(false) {}
-    const isc::dns::Opcode* opcode;
-    bool static_code;
-};
-
-
 extern PyTypeObject opcode_type;
 
-bool initModulePart_Opcode(PyObject* mod);
+/// This is a simple shortcut to create a python Opcode object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createOpcodeObject(const Opcode& source);
+
+/// \brief Checks if the given python object is a Opcode object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Opcode, false otherwise
+bool PyOpcode_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Opcode object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Opcode; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyOpcode_Check()
+///
+/// \note This is not a copy; if the Opcode is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param opcode_obj The opcode object to convert
+const Opcode& PyOpcode_ToOpcode(const PyObject* opcode_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index 91ec3d1..71be32c 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -29,34 +29,42 @@
 
 #include <config.h>
 
-#include <exceptions/exceptions.h>
-
-#include <util/buffer.h>
+#include "pydnspp_common.h"
+/* Note that we do forward declarations of the initialization functions here,
+ * and these are not defined in headers (since they are not to be used in any
+ * other place */
+namespace isc {
+namespace dns {
+namespace python {
+namespace internal {
+
+bool initModulePart_EDNS(PyObject* mod);
+bool initModulePart_Message(PyObject* mod);
+bool initModulePart_MessageRenderer(PyObject* mod);
+bool initModulePart_Name(PyObject* mod);
+bool initModulePart_Opcode(PyObject* mod);
+bool initModulePart_Question(PyObject* mod);
+bool initModulePart_Rcode(PyObject* mod);
+bool initModulePart_Rdata(PyObject* mod);
+bool initModulePart_RRClass(PyObject* mod);
+bool initModulePart_RRset(PyObject* mod);
+bool initModulePart_RRTTL(PyObject* mod);
+bool initModulePart_RRType(PyObject* mod);
+bool initModulePart_TSIGError(PyObject* mod);
+bool initModulePart_TSIGKey(PyObject* mod);
+bool initModulePart_TSIGKeyRing(PyObject* mod);
+bool initModulePart_TSIGContext(PyObject* mod);
+bool initModulePart_TSIG(PyObject* mod);
+bool initModulePart_TSIGRecord(PyObject* mod);
 
-#include <dns/exceptions.h>
-#include <dns/name.h>
-#include <dns/messagerenderer.h>
+}
+} // namespace python
+} // namespace dns
+} // namespace isc
 
-#include "pydnspp_common.h"
-#include "messagerenderer_python.h"
-#include "name_python.h"
-#include "rrclass_python.h"
-#include "rrtype_python.h"
-#include "rrttl_python.h"
-#include "rdata_python.h"
-#include "rcode_python.h"
-#include "opcode_python.h"
-#include "rrset_python.h"
-#include "tsigkey_python.h"
-#include "tsig_rdata_python.h"
-#include "tsigerror_python.h"
-#include "tsigrecord_python.h"
-#include "tsig_python.h"
-#include "question_python.h"
-#include "message_python.h"
-#include "edns_python.h"
 
 using namespace isc::dns::python;
+using namespace isc::dns::python::internal;
 
 //
 // Definition of the module
diff --git a/src/lib/dns/python/pydnspp_towire.h b/src/lib/dns/python/pydnspp_towire.h
index 66362a0..e987a29 100644
--- a/src/lib/dns/python/pydnspp_towire.h
+++ b/src/lib/dns/python/pydnspp_towire.h
@@ -93,10 +93,10 @@ toWireWrapper(const PYSTRUCT* const self, PyObject* args) {
         }
 
         // To MessageRenderer version
-        s_MessageRenderer* renderer;
+        PyObject* renderer;
         if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &renderer)) {
             const unsigned int n = TOWIRECALLER(*self->cppobj)(
-                *renderer->messagerenderer);
+                PyMessageRenderer_ToMessageRenderer(renderer));
 
             return (Py_BuildValue("I", n));
         }
diff --git a/src/lib/dns/python/question_python.cc b/src/lib/dns/python/question_python.cc
index 234009e..953a0c3 100644
--- a/src/lib/dns/python/question_python.cc
+++ b/src/lib/dns/python/question_python.cc
@@ -32,6 +32,10 @@ using namespace isc::util;
 using namespace isc;
 
 namespace {
+class s_Question : public PyObject {
+public:
+    isc::dns::QuestionPtr cppobj;
+};
 
 static int Question_init(s_Question* self, PyObject* args);
 static void Question_destroy(s_Question* self);
@@ -79,9 +83,9 @@ Question_init(s_Question* self, PyObject* args) {
     // that if we try several like here. Otherwise the *next* python
     // call will suddenly appear to throw an exception.
     // (the way to do exceptions is to set PyErr and return -1)
-    s_Name* name;
-    s_RRClass* rrclass;
-    s_RRType* rrtype;
+    PyObject* name;
+    PyObject* rrclass;
+    PyObject* rrtype;
 
     const char* b;
     Py_ssize_t len;
@@ -89,18 +93,18 @@ Question_init(s_Question* self, PyObject* args) {
 
     try {
         if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &name,
-                                               &rrclass_type, &rrclass,
-                                               &rrtype_type, &rrtype
+                                             &rrclass_type, &rrclass,
+                                             &rrtype_type, &rrtype
            )) {
-            self->question = QuestionPtr(new Question(*name->cppobj,
-                                         *rrclass->cppobj,
-                                         *rrtype->cppobj));
+            self->cppobj = QuestionPtr(new Question(PyName_ToName(name),
+                                                    PyRRClass_ToRRClass(rrclass),
+                                                    PyRRType_ToRRType(rrtype)));
             return (0);
         } else if (PyArg_ParseTuple(args, "y#|I", &b, &len, &position)) {
             PyErr_Clear();
             InputBuffer inbuf(b, len);
             inbuf.setPosition(position);
-            self->question = QuestionPtr(new Question(inbuf));
+            self->cppobj = QuestionPtr(new Question(inbuf));
             return (0);
         }
     } catch (const DNSMessageFORMERR& dmfe) {
@@ -117,7 +121,7 @@ Question_init(s_Question* self, PyObject* args) {
         return (-1);
     }
 
-    self->question = QuestionPtr();
+    self->cppobj = QuestionPtr();
 
     PyErr_Clear();
     PyErr_SetString(PyExc_TypeError,
@@ -127,52 +131,29 @@ Question_init(s_Question* self, PyObject* args) {
 
 static void
 Question_destroy(s_Question* self) {
-    self->question.reset();
+    self->cppobj.reset();
     Py_TYPE(self)->tp_free(self);
 }
 
 static PyObject*
 Question_getName(s_Question* self) {
-    s_Name* name;
-
-    // is this the best way to do this?
-    name = static_cast<s_Name*>(name_type.tp_alloc(&name_type, 0));
-    if (name != NULL) {
-        name->cppobj = new Name(self->question->getName());
-    }
-
-    return (name);
+    return (createNameObject(self->cppobj->getName()));
 }
 
 static PyObject*
 Question_getType(s_Question* self) {
-    s_RRType* rrtype;
-
-    rrtype = static_cast<s_RRType*>(rrtype_type.tp_alloc(&rrtype_type, 0));
-    if (rrtype != NULL) {
-        rrtype->cppobj = new RRType(self->question->getType());
-    }
-
-    return (rrtype);
+    return (createRRTypeObject(self->cppobj->getType()));
 }
 
 static PyObject*
 Question_getClass(s_Question* self) {
-    s_RRClass* rrclass;
-
-    rrclass = static_cast<s_RRClass*>(rrclass_type.tp_alloc(&rrclass_type, 0));
-    if (rrclass != NULL) {
-        rrclass->cppobj = new RRClass(self->question->getClass());
-    }
-
-    return (rrclass);
+    return (createRRClassObject(self->cppobj->getClass()));
 }
 
-
 static PyObject*
 Question_toText(s_Question* self) {
     // Py_BuildValue makes python objects from native data
-    return (Py_BuildValue("s", self->question->toText().c_str()));
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
 }
 
 static PyObject*
@@ -186,14 +167,14 @@ Question_str(PyObject* self) {
 static PyObject*
 Question_toWire(s_Question* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
 
         // Max length is Name::MAX_WIRE + rrclass (2) + rrtype (2)
         OutputBuffer buffer(Name::MAX_WIRE + 4);
-        self->question->toWire(buffer);
+        self->cppobj->toWire(buffer);
         PyObject* n = PyBytes_FromStringAndSize(static_cast<const char*>(buffer.getData()),
                                                 buffer.getLength());
         PyObject* result = PySequence_InPlaceConcat(bytes_o, n);
@@ -202,7 +183,7 @@ Question_toWire(s_Question* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->question->toWire(*mr->messagerenderer);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -273,6 +254,7 @@ PyTypeObject question_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool
 initModulePart_Question(PyObject* mod) {
     // Add the exceptions to the module
@@ -289,6 +271,26 @@ initModulePart_Question(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+PyObject*
+createQuestionObject(const Question& source) {
+    s_Question* question =
+        static_cast<s_Question*>(question_type.tp_alloc(&question_type, 0));
+    question->cppobj = QuestionPtr(new Question(source));
+    return (question);
+}
+
+bool
+PyQuestion_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &question_type));
+}
+
+const Question&
+PyQuestion_ToQuestion(const PyObject* question_obj) {
+    const s_Question* question = static_cast<const s_Question*>(question_obj);
+    return (*question->cppobj);
+}
 
 } // end python namespace
 } // end dns namespace
diff --git a/src/lib/dns/python/question_python.h b/src/lib/dns/python/question_python.h
index a4ee537..1971b4b 100644
--- a/src/lib/dns/python/question_python.h
+++ b/src/lib/dns/python/question_python.h
@@ -30,14 +30,34 @@ namespace python {
 //
 extern PyObject* po_EmptyQuestion;
 
-class s_Question : public PyObject {
-public:
-    isc::dns::QuestionPtr question;
-};
-
 extern PyTypeObject question_type;
 
-bool initModulePart_Question(PyObject* mod);
+/// This is a simple shortcut to create a python Question object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createQuestionObject(const Question& source);
+
+/// \brief Checks if the given python object is a Question object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Question, false otherwise
+bool PyQuestion_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Question object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Question; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyQuestion_Check()
+///
+/// \note This is not a copy; if the Question is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param question_obj The question object to convert
+const Question& PyQuestion_ToQuestion(const PyObject* question_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/rcode_python.cc b/src/lib/dns/python/rcode_python.cc
index 0208d98..2e51003 100644
--- a/src/lib/dns/python/rcode_python.cc
+++ b/src/lib/dns/python/rcode_python.cc
@@ -15,19 +15,39 @@
 #include <Python.h>
 
 #include <exceptions/exceptions.h>
-
 #include <dns/rcode.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "pydnspp_common.h"
 #include "rcode_python.h"
 
 using namespace isc::dns;
 using namespace isc::dns::python;
-
-// Trivial constructor.
-s_Rcode::s_Rcode() : cppobj(NULL), static_code(false) {}
+using namespace isc::util::python;
 
 namespace {
+// The s_* Class simply covers one instantiation of the object.
+//
+// We added a helper variable static_code here
+// Since we can create Rcodes dynamically with Rcode(int), but also
+// use the static globals (Rcode::NOERROR() etc), we use this
+// variable to see if the code came from one of the latter, in which
+// case Rcode_destroy should not free it (the other option is to
+// allocate new Rcodes for every use of the static ones, but this
+// seems more efficient).
+//
+// Follow-up note: we don't have to use the proxy function in the python lib;
+// we can just define class specific constants directly (see TSIGError).
+// We should make this cleanup later.
+class s_Rcode : public PyObject {
+public:
+    s_Rcode() : cppobj(NULL), static_code(false) {};
+    const Rcode* cppobj;
+    bool static_code;
+};
+
+typedef CPPPyObjectContainer<s_Rcode, Rcode> RcodeContainer;
+
 int Rcode_init(s_Rcode* const self, PyObject* args);
 void Rcode_destroy(s_Rcode* const self);
 
@@ -361,6 +381,7 @@ PyTypeObject rcode_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool
 initModulePart_Rcode(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -413,6 +434,25 @@ initModulePart_Rcode(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+PyObject*
+createRcodeObject(const Rcode& source) {
+    RcodeContainer container = PyObject_New(s_Rcode, &rcode_type);
+    container.set(new Rcode(source));
+    return (container.release());
+}
+
+bool
+PyRcode_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &rcode_type));
+}
+
+const Rcode&
+PyRcode_ToRcode(const PyObject* rcode_obj) {
+    const s_Rcode* rcode = static_cast<const s_Rcode*>(rcode_obj);
+    return (*rcode->cppobj);
+}
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/rcode_python.h b/src/lib/dns/python/rcode_python.h
index 5d9b91d..89969c7 100644
--- a/src/lib/dns/python/rcode_python.h
+++ b/src/lib/dns/python/rcode_python.h
@@ -23,29 +23,34 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object.
-//
-// We added a helper variable static_code here
-// Since we can create Rcodes dynamically with Rcode(int), but also
-// use the static globals (Rcode::NOERROR() etc), we use this
-// variable to see if the code came from one of the latter, in which
-// case Rcode_destroy should not free it (the other option is to
-// allocate new Rcodes for every use of the static ones, but this
-// seems more efficient).
-//
-// Follow-up note: we don't have to use the proxy function in the python lib;
-// we can just define class specific constants directly (see TSIGError).
-// We should make this cleanup later.
-class s_Rcode : public PyObject {
-public:
-    s_Rcode();
-    const Rcode* cppobj;
-    bool static_code;
-};
-
 extern PyTypeObject rcode_type;
 
-bool initModulePart_Rcode(PyObject* mod);
+/// This is a simple shortcut to create a python Rcode object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createRcodeObject(const Rcode& source);
+
+/// \brief Checks if the given python object is a Rcode object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Rcode, false otherwise
+bool PyRcode_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Rcode object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Rcode; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRcode_Check()
+///
+/// \note This is not a copy; if the Rcode is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rcode_obj The rcode object to convert
+const Rcode& PyRcode_ToRcode(const PyObject* rcode_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/rdata_python.cc b/src/lib/dns/python/rdata_python.cc
index 8596d74..3167fca 100644
--- a/src/lib/dns/python/rdata_python.cc
+++ b/src/lib/dns/python/rdata_python.cc
@@ -17,6 +17,7 @@
 #include <dns/rdata.h>
 #include <dns/messagerenderer.h>
 #include <util/buffer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "rdata_python.h"
 #include "rrtype_python.h"
@@ -26,9 +27,16 @@
 using namespace isc::dns;
 using namespace isc::dns::python;
 using namespace isc::util;
+using namespace isc::util::python;
 using namespace isc::dns::rdata;
 
 namespace {
+class s_Rdata : public PyObject {
+public:
+    isc::dns::rdata::ConstRdataPtr cppobj;
+};
+
+typedef CPPPyObjectContainer<s_Rdata, Rdata> RdataContainer;
 
 //
 // We declare the functions here, the definitions are below
@@ -68,8 +76,8 @@ PyMethodDef Rdata_methods[] = {
 
 int
 Rdata_init(s_Rdata* self, PyObject* args) {
-    s_RRType* rrtype;
-    s_RRClass* rrclass;
+    PyObject* rrtype;
+    PyObject* rrclass;
     const char* s;
     const char* data;
     Py_ssize_t len;
@@ -78,13 +86,15 @@ Rdata_init(s_Rdata* self, PyObject* args) {
     if (PyArg_ParseTuple(args, "O!O!s", &rrtype_type, &rrtype,
                                         &rrclass_type, &rrclass,
                                         &s)) {
-        self->rdata = createRdata(*rrtype->cppobj, *rrclass->cppobj, s);
+        self->cppobj = createRdata(PyRRType_ToRRType(rrtype),
+                                   PyRRClass_ToRRClass(rrclass), s);
         return (0);
     } else if (PyArg_ParseTuple(args, "O!O!y#", &rrtype_type, &rrtype,
                                 &rrclass_type, &rrclass, &data, &len)) {
         InputBuffer input_buffer(data, len);
-        self->rdata = createRdata(*rrtype->cppobj, *rrclass->cppobj,
-                                  input_buffer, len);
+        self->cppobj = createRdata(PyRRType_ToRRType(rrtype),
+                                   PyRRClass_ToRRClass(rrclass),
+                                   input_buffer, len);
         return (0);
     }
 
@@ -95,14 +105,14 @@ void
 Rdata_destroy(s_Rdata* self) {
     // Clear the shared_ptr so that its reference count is zero
     // before we call tp_free() (there is no direct release())
-    self->rdata.reset();
+    self->cppobj.reset();
     Py_TYPE(self)->tp_free(self);
 }
 
 PyObject*
 Rdata_toText(s_Rdata* self) {
     // Py_BuildValue makes python objects from native data
-    return (Py_BuildValue("s", self->rdata->toText().c_str()));
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
 }
 
 PyObject*
@@ -116,13 +126,13 @@ Rdata_str(PyObject* self) {
 PyObject*
 Rdata_toWire(s_Rdata* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
 
         OutputBuffer buffer(4);
-        self->rdata->toWire(buffer);
+        self->cppobj->toWire(buffer);
         PyObject* rd_bytes = PyBytes_FromStringAndSize(static_cast<const char*>(buffer.getData()), buffer.getLength());
         PyObject* result = PySequence_InPlaceConcat(bytes_o, rd_bytes);
         // We need to release the object we temporarily created here
@@ -130,7 +140,7 @@ Rdata_toWire(s_Rdata* self, PyObject* args) {
         Py_DECREF(rd_bytes);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->rdata->toWire(*mr->messagerenderer);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -153,24 +163,24 @@ RData_richcmp(s_Rdata* self, s_Rdata* other, int op) {
 
     switch (op) {
     case Py_LT:
-        c = self->rdata->compare(*other->rdata) < 0;
+        c = self->cppobj->compare(*other->cppobj) < 0;
         break;
     case Py_LE:
-        c = self->rdata->compare(*other->rdata) < 0 ||
-            self->rdata->compare(*other->rdata) == 0;
+        c = self->cppobj->compare(*other->cppobj) < 0 ||
+            self->cppobj->compare(*other->cppobj) == 0;
         break;
     case Py_EQ:
-        c = self->rdata->compare(*other->rdata) == 0;
+        c = self->cppobj->compare(*other->cppobj) == 0;
         break;
     case Py_NE:
-        c = self->rdata->compare(*other->rdata) != 0;
+        c = self->cppobj->compare(*other->cppobj) != 0;
         break;
     case Py_GT:
-        c = self->rdata->compare(*other->rdata) > 0;
+        c = self->cppobj->compare(*other->cppobj) > 0;
         break;
     case Py_GE:
-        c = self->rdata->compare(*other->rdata) > 0 ||
-            self->rdata->compare(*other->rdata) == 0;
+        c = self->cppobj->compare(*other->cppobj) > 0 ||
+            self->cppobj->compare(*other->cppobj) == 0;
         break;
     default:
         PyErr_SetString(PyExc_IndexError,
@@ -253,6 +263,7 @@ PyTypeObject rdata_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 // Module Initialization, all statics are initialized here
 bool
 initModulePart_Rdata(PyObject* mod) {
@@ -279,6 +290,30 @@ initModulePart_Rdata(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+PyObject*
+createRdataObject(ConstRdataPtr source) {
+    s_Rdata* py_rdata =
+        static_cast<s_Rdata*>(rdata_type.tp_alloc(&rdata_type, 0));
+    if (py_rdata == NULL) {
+        isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+                  "probably due to short memory");
+    }
+    py_rdata->cppobj = source;
+    return (py_rdata);
+}
+
+bool
+PyRdata_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &rdata_type));
+}
+
+const Rdata&
+PyRdata_ToRdata(const PyObject* rdata_obj) {
+    const s_Rdata* rdata = static_cast<const s_Rdata*>(rdata_obj);
+    return (*rdata->cppobj);
+}
 
 } // end python namespace
 } // end dns namespace
diff --git a/src/lib/dns/python/rdata_python.h b/src/lib/dns/python/rdata_python.h
index e9c8667..8db6821 100644
--- a/src/lib/dns/python/rdata_python.h
+++ b/src/lib/dns/python/rdata_python.h
@@ -30,14 +30,34 @@ namespace python {
 //
 extern PyObject* po_EmptyRdata;
 
-class s_Rdata : public PyObject {
-public:
-    isc::dns::rdata::RdataPtr rdata;
-};
-
 extern PyTypeObject rdata_type;
 
-bool initModulePart_Rdata(PyObject* mod);
+/// This is a simple shortcut to create a python Rdata object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createRdataObject(isc::dns::rdata::ConstRdataPtr source);
+
+/// \brief Checks if the given python object is a Rdata object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Rdata, false otherwise
+bool PyRdata_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Rdata object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Rdata; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRdata_Check()
+///
+/// \note This is not a copy; if the Rdata is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rdata_obj The rdata object to convert
+const isc::dns::rdata::Rdata& PyRdata_ToRdata(const PyObject* rdata_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/rrclass_python.cc b/src/lib/dns/python/rrclass_python.cc
index a2d4688..87ba32e 100644
--- a/src/lib/dns/python/rrclass_python.cc
+++ b/src/lib/dns/python/rrclass_python.cc
@@ -28,6 +28,12 @@ using namespace isc::dns::python;
 using namespace isc::util;
 using namespace isc::util::python;
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_RRClass : public PyObject {
+public:
+    s_RRClass() : cppobj(NULL) {};
+    RRClass* cppobj;
+};
 
 //
 // We declare the functions here, the definitions are below
@@ -155,7 +161,7 @@ RRClass_str(PyObject* self) {
 PyObject*
 RRClass_toWire(s_RRClass* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -169,7 +175,7 @@ RRClass_toWire(s_RRClass* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->messagerenderer);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -331,6 +337,7 @@ PyTypeObject rrclass_type = {
 
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_RRClass(PyObject* mod) {
     // Add the exceptions to the module
@@ -353,6 +360,7 @@ initModulePart_RRClass(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 PyObject*
 createRRClassObject(const RRClass& source) {
@@ -367,9 +375,9 @@ PyRRClass_Check(PyObject* obj) {
     return (PyObject_TypeCheck(obj, &rrclass_type));
 }
 
-RRClass&
-PyRRClass_ToRRClassPtr(PyObject* rrclass_obj) {
-    s_RRClass* rrclass = static_cast<s_RRClass*>(rrclass_obj);
+const RRClass&
+PyRRClass_ToRRClass(const PyObject* rrclass_obj) {
+    const s_RRClass* rrclass = static_cast<const s_RRClass*>(rrclass_obj);
     return (*rrclass->cppobj);
 }
 
diff --git a/src/lib/dns/python/rrclass_python.h b/src/lib/dns/python/rrclass_python.h
index 6ad733f..f11b817 100644
--- a/src/lib/dns/python/rrclass_python.h
+++ b/src/lib/dns/python/rrclass_python.h
@@ -26,21 +26,8 @@ namespace python {
 extern PyObject* po_InvalidRRClass;
 extern PyObject* po_IncompleteRRClass;
 
-//
-// Declaration of the custom exceptions
-// Initialization and addition of these go in the module init at the
-// end
-//
-// The s_* Class simply covers one instantiation of the object
-class s_RRClass : public PyObject {
-public:
-    RRClass* cppobj;
-};
-
 extern PyTypeObject rrclass_type;
 
-bool initModulePart_RRClass(PyObject* mod);
-
 /// This is a simple shortcut to create a python RRClass object (in the
 /// form of a pointer to PyObject) with minimal exception safety.
 /// On success, it returns a valid pointer to PyObject with a reference
@@ -66,7 +53,7 @@ bool PyRRClass_Check(PyObject* obj);
 /// may be destroyed, the caller must copy it itself.
 ///
 /// \param rrclass_obj The rrclass object to convert
-RRClass& PyRRClass_ToRRClass(PyObject* rrclass_obj);
+const RRClass& PyRRClass_ToRRClass(const PyObject* rrclass_obj);
 
 
 } // namespace python
diff --git a/src/lib/dns/python/rrset_python.cc b/src/lib/dns/python/rrset_python.cc
index cdcd50f..2c33920 100644
--- a/src/lib/dns/python/rrset_python.cc
+++ b/src/lib/dns/python/rrset_python.cc
@@ -36,6 +36,19 @@ using namespace isc::util::python;
 
 namespace {
 
+// The s_* Class simply coverst one instantiation of the object
+
+// Using a shared_ptr here should not really be necessary (PyObject
+// is already reference-counted), however internally on the cpp side,
+// not doing so might result in problems, since we can't copy construct
+// rdata field, adding them to rrsets results in a problem when the
+// rrset is destroyed later
+class s_RRset : public PyObject {
+public:
+    isc::dns::RRsetPtr cppobj;
+};
+
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_RRset, RRset> RRsetContainer;
 
@@ -93,22 +106,24 @@ PyMethodDef RRset_methods[] = {
 
 int
 RRset_init(s_RRset* self, PyObject* args) {
-    s_Name* name;
-    s_RRClass* rrclass;
-    s_RRType* rrtype;
-    s_RRTTL* rrttl;
+    PyObject* name;
+    PyObject* rrclass;
+    PyObject* rrtype;
+    PyObject* rrttl;
 
     if (PyArg_ParseTuple(args, "O!O!O!O!", &name_type, &name,
                                            &rrclass_type, &rrclass,
                                            &rrtype_type, &rrtype,
                                            &rrttl_type, &rrttl
        )) {
-        self->rrset = RRsetPtr(new RRset(*name->cppobj, *rrclass->cppobj,
-                                *rrtype->cppobj, *rrttl->rrttl));
+        self->cppobj = RRsetPtr(new RRset(PyName_ToName(name),
+                                          PyRRClass_ToRRClass(rrclass),
+                                          PyRRType_ToRRType(rrtype),
+                                          PyRRTTL_ToRRTTL(rrttl)));
         return (0);
     }
 
-    self->rrset = RRsetPtr();
+    self->cppobj = RRsetPtr();
     return (-1);
 }
 
@@ -116,108 +131,59 @@ void
 RRset_destroy(s_RRset* self) {
     // Clear the shared_ptr so that its reference count is zero
     // before we call tp_free() (there is no direct release())
-    self->rrset.reset();
+    self->cppobj.reset();
     Py_TYPE(self)->tp_free(self);
 }
 
 PyObject*
 RRset_getRdataCount(s_RRset* self) {
-    return (Py_BuildValue("I", self->rrset->getRdataCount()));
+    return (Py_BuildValue("I", self->cppobj->getRdataCount()));
 }
 
 PyObject*
 RRset_getName(s_RRset* self) {
-    s_Name* name;
-
-    // is this the best way to do this?
-    name = static_cast<s_Name*>(name_type.tp_alloc(&name_type, 0));
-    if (name != NULL) {
-        name->cppobj = new Name(self->rrset->getName());
-        if (name->cppobj == NULL)
-          {
-            Py_DECREF(name);
-            return (NULL);
-          }
-    }
-
-    return (name);
+    return (createNameObject(self->cppobj->getName()));
 }
 
 PyObject*
 RRset_getClass(s_RRset* self) {
-    s_RRClass* rrclass;
-
-    rrclass = static_cast<s_RRClass*>(rrclass_type.tp_alloc(&rrclass_type, 0));
-    if (rrclass != NULL) {
-        rrclass->cppobj = new RRClass(self->rrset->getClass());
-        if (rrclass->cppobj == NULL)
-          {
-            Py_DECREF(rrclass);
-            return (NULL);
-          }
-    }
-
-    return (rrclass);
+    return (createRRClassObject(self->cppobj->getClass()));
 }
 
 PyObject*
 RRset_getType(s_RRset* self) {
-    s_RRType* rrtype;
-
-    rrtype = static_cast<s_RRType*>(rrtype_type.tp_alloc(&rrtype_type, 0));
-    if (rrtype != NULL) {
-        rrtype->cppobj = new RRType(self->rrset->getType());
-        if (rrtype->cppobj == NULL)
-          {
-            Py_DECREF(rrtype);
-            return (NULL);
-          }
-    }
-
-    return (rrtype);
+    return (createRRTypeObject(self->cppobj->getType()));
 }
 
 PyObject*
 RRset_getTTL(s_RRset* self) {
-    s_RRTTL* rrttl;
-
-    rrttl = static_cast<s_RRTTL*>(rrttl_type.tp_alloc(&rrttl_type, 0));
-    if (rrttl != NULL) {
-        rrttl->rrttl = new RRTTL(self->rrset->getTTL());
-        if (rrttl->rrttl == NULL)
-          {
-            Py_DECREF(rrttl);
-            return (NULL);
-          }
-    }
-
-    return (rrttl);
+    return (createRRTTLObject(self->cppobj->getTTL()));
 }
 
 PyObject*
 RRset_setName(s_RRset* self, PyObject* args) {
-    s_Name* name;
+    PyObject* name;
     if (!PyArg_ParseTuple(args, "O!", &name_type, &name)) {
         return (NULL);
     }
-    self->rrset->setName(*name->cppobj);
+    self->cppobj->setName(PyName_ToName(name));
     Py_RETURN_NONE;
 }
 
 PyObject*
 RRset_setTTL(s_RRset* self, PyObject* args) {
-    s_RRTTL* rrttl;
+    PyObject* rrttl;
     if (!PyArg_ParseTuple(args, "O!", &rrttl_type, &rrttl)) {
         return (NULL);
     }
-    self->rrset->setTTL(*rrttl->rrttl);
+    self->cppobj->setTTL(PyRRTTL_ToRRTTL(rrttl));
     Py_RETURN_NONE;
 }
 
 PyObject*
 RRset_toText(s_RRset* self) {
     try {
-        return (Py_BuildValue("s", self->rrset->toText().c_str()));
+        return (Py_BuildValue("s", self->cppobj->toText().c_str()));
     } catch (const EmptyRRset& ers) {
         PyErr_SetString(po_EmptyRRset, ers.what());
         return (NULL);
@@ -235,14 +201,14 @@ RRset_str(PyObject* self) {
 PyObject*
 RRset_toWire(s_RRset* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     try {
         if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
             PyObject* bytes_o = bytes;
 
             OutputBuffer buffer(4096);
-            self->rrset->toWire(buffer);
+            self->cppobj->toWire(buffer);
             PyObject* n = PyBytes_FromStringAndSize(static_cast<const char*>(buffer.getData()), buffer.getLength());
             PyObject* result = PySequence_InPlaceConcat(bytes_o, n);
             // We need to release the object we temporarily created here
@@ -250,7 +216,7 @@ RRset_toWire(s_RRset* self, PyObject* args) {
             Py_DECREF(n);
             return (result);
         } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-            self->rrset->toWire(*mr->messagerenderer);
+            self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
             // If we return NULL it is seen as an error, so use this for
             // None returns
             Py_RETURN_NONE;
@@ -268,12 +234,12 @@ RRset_toWire(s_RRset* self, PyObject* args) {
 
 PyObject*
 RRset_addRdata(s_RRset* self, PyObject* args) {
-    s_Rdata* rdata;
+    PyObject* rdata;
     if (!PyArg_ParseTuple(args, "O!", &rdata_type, &rdata)) {
         return (NULL);
     }
     try {
-        self->rrset->addRdata(*rdata->rdata);
+        self->cppobj->addRdata(PyRdata_ToRdata(rdata));
         Py_RETURN_NONE;
     } catch (const std::bad_cast&) {
         PyErr_Clear();
@@ -287,20 +253,13 @@ PyObject*
 RRset_getRdata(s_RRset* self) {
     PyObject* list = PyList_New(0);
 
-    RdataIteratorPtr it = self->rrset->getRdataIterator();
+    RdataIteratorPtr it = self->cppobj->getRdataIterator();
 
     for (; !it->isLast(); it->next()) {
-        s_Rdata *rds = static_cast<s_Rdata*>(rdata_type.tp_alloc(&rdata_type, 0));
-        if (rds != NULL) {
-            // hmz them iterators/shared_ptrs and private constructors
-            // make this a bit weird, so we create a new one with
-            // the data available
-            const rdata::Rdata *rd = &it->getCurrent();
-            rds->rdata = createRdata(self->rrset->getType(), self->rrset->getClass(), *rd);
-            PyList_Append(list, rds);
-        } else {
-            return (NULL);
-        }
+        const rdata::Rdata *rd = &it->getCurrent();
+        PyList_Append(list,
+                      createRdataObject(createRdata(self->cppobj->getType(),
+                                        self->cppobj->getClass(), *rd)));
     }
 
     return (list);
@@ -308,7 +267,7 @@ RRset_getRdata(s_RRset* self) {
 
 PyObject*
 RRset_removeRRsig(s_RRset* self) {
-    self->rrset->removeRRsig();
+    self->cppobj->removeRRsig();
     Py_RETURN_NONE;
 }
 
@@ -393,6 +352,7 @@ PyTypeObject rrset_type = {
 
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_RRset(PyObject* mod) {
     // Add the exceptions to the module
@@ -417,11 +377,12 @@ initModulePart_RRset(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 PyObject*
 createRRsetObject(const RRset& source) {
-    isc::dns::python::s_RRset* py_rrset = static_cast<isc::dns::python::s_RRset*>(
-        isc::dns::python::rrset_type.tp_alloc(&isc::dns::python::rrset_type, 0));
+    s_RRset* py_rrset =
+        static_cast<s_RRset*>(rrset_type.tp_alloc(&rrset_type, 0));
     if (py_rrset == NULL) {
         isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
                   "probably due to short memory");
@@ -430,18 +391,18 @@ createRRsetObject(const RRset& source) {
     // RRsets are noncopyable, so as a workaround we recreate a new one
     // and copy over all content
     try {
-        py_rrset->rrset = isc::dns::RRsetPtr(
+        py_rrset->cppobj = isc::dns::RRsetPtr(
             new isc::dns::RRset(source.getName(), source.getClass(),
                                 source.getType(), source.getTTL()));
 
         isc::dns::RdataIteratorPtr rdata_it(source.getRdataIterator());
         for (rdata_it->first(); !rdata_it->isLast(); rdata_it->next()) {
-            py_rrset->rrset->addRdata(rdata_it->getCurrent());
+            py_rrset->cppobj->addRdata(rdata_it->getCurrent());
         }
 
         isc::dns::RRsetPtr sigs = source.getRRsig();
         if (sigs) {
-            py_rrset->rrset->addRRsig(sigs);
+            py_rrset->cppobj->addRRsig(sigs);
         }
         return (py_rrset);
     } catch (const std::bad_alloc&) {
@@ -458,9 +419,14 @@ PyRRset_Check(PyObject* obj) {
 RRset&
 PyRRset_ToRRset(PyObject* rrset_obj) {
     s_RRset* rrset = static_cast<s_RRset*>(rrset_obj);
-    return (*rrset->rrset);
+    return (*rrset->cppobj);
 }
 
+RRsetPtr
+PyRRset_ToRRsetPtr(PyObject* rrset_obj) {
+    s_RRset* rrset = static_cast<s_RRset*>(rrset_obj);
+    return (rrset->cppobj);
+}
 
 
 } // end python namespace
diff --git a/src/lib/dns/python/rrset_python.h b/src/lib/dns/python/rrset_python.h
index e43de28..04d305f 100644
--- a/src/lib/dns/python/rrset_python.h
+++ b/src/lib/dns/python/rrset_python.h
@@ -32,22 +32,8 @@ namespace python {
 //
 extern PyObject* po_EmptyRRset;
 
-// The s_* Class simply coverst one instantiation of the object
-
-// Using a shared_ptr here should not really be necessary (PyObject
-// is already reference-counted), however internally on the cpp side,
-// not doing so might result in problems, since we can't copy construct
-// rdata field, adding them to rrsets results in a problem when the
-// rrset is destroyed later
-class s_RRset : public PyObject {
-public:
-    isc::dns::RRsetPtr rrset;
-};
-
 extern PyTypeObject rrset_type;
 
-bool initModulePart_RRset(PyObject* mod);
-
 /// This is a simple shortcut to create a python RRset object (in the
 /// form of a pointer to PyObject) with minimal exception safety.
 /// On success, it returns a valid pointer to PyObject with a reference
@@ -75,6 +61,15 @@ bool PyRRset_Check(PyObject* obj);
 /// \param rrset_obj The rrset object to convert
 RRset& PyRRset_ToRRset(PyObject* rrset_obj);
 
+/// \brief Returns the shared_ptr of the RRset object contained within the
+///        given Python object.
+///
+/// \note The given object MUST be of type RRset; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRRset_Check()
+///
+/// \param rrset_obj The rrset object to convert
+RRsetPtr PyRRset_ToRRsetPtr(PyObject* rrset_obj);
+
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/rrttl_python.cc b/src/lib/dns/python/rrttl_python.cc
index e6bab0c..bea1d17 100644
--- a/src/lib/dns/python/rrttl_python.cc
+++ b/src/lib/dns/python/rrttl_python.cc
@@ -18,6 +18,7 @@
 #include <dns/rrttl.h>
 #include <dns/messagerenderer.h>
 #include <util/buffer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "rrttl_python.h"
 #include "pydnspp_common.h"
@@ -27,11 +28,17 @@ using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::python;
 using namespace isc::util;
+using namespace isc::util::python;
 
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_RRTTL : public PyObject {
+public:
+    s_RRTTL() : cppobj(NULL) {};
+    isc::dns::RRTTL* cppobj;
+};
 
-int RRTTL_init(s_RRTTL* self, PyObject* args);
-void RRTTL_destroy(s_RRTTL* self);
+typedef CPPPyObjectContainer<s_RRTTL, RRTTL> RRTTLContainer;
 
 PyObject* RRTTL_toText(s_RRTTL* self);
 // This is a second version of toText, we need one where the argument
@@ -76,7 +83,7 @@ RRTTL_init(s_RRTTL* self, PyObject* args) {
     // (the way to do exceptions is to set PyErr and return -1)
     try {
         if (PyArg_ParseTuple(args, "s", &s)) {
-            self->rrttl = new RRTTL(s);
+            self->cppobj = new RRTTL(s);
             return (0);
         } else if (PyArg_ParseTuple(args, "L", &i)) {
             PyErr_Clear();
@@ -84,7 +91,7 @@ RRTTL_init(s_RRTTL* self, PyObject* args) {
                 PyErr_SetString(PyExc_ValueError, "RR TTL number out of range");
                 return (-1);
             }
-            self->rrttl = new RRTTL(i);
+            self->cppobj = new RRTTL(i);
             return (0);
         } else if (PyArg_ParseTuple(args, "O", &bytes) &&
                    PySequence_Check(bytes)) {
@@ -95,7 +102,7 @@ RRTTL_init(s_RRTTL* self, PyObject* args) {
                 return (result);
             }
             InputBuffer ib(&data[0], size);
-            self->rrttl = new RRTTL(ib);
+            self->cppobj = new RRTTL(ib);
             PyErr_Clear();
             return (0);
         }
@@ -121,15 +128,15 @@ RRTTL_init(s_RRTTL* self, PyObject* args) {
 
 void
 RRTTL_destroy(s_RRTTL* self) {
-    delete self->rrttl;
-    self->rrttl = NULL;
+    delete self->cppobj;
+    self->cppobj = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 
 PyObject*
 RRTTL_toText(s_RRTTL* self) {
     // Py_BuildValue makes python objects from native data
-    return (Py_BuildValue("s", self->rrttl->toText().c_str()));
+    return (Py_BuildValue("s", self->cppobj->toText().c_str()));
 }
 
 PyObject*
@@ -143,13 +150,13 @@ RRTTL_str(PyObject* self) {
 PyObject*
 RRTTL_toWire(s_RRTTL* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
 
         OutputBuffer buffer(4);
-        self->rrttl->toWire(buffer);
+        self->cppobj->toWire(buffer);
         PyObject* n = PyBytes_FromStringAndSize(static_cast<const char*>(buffer.getData()),
                                                 buffer.getLength());
         PyObject* result = PySequence_InPlaceConcat(bytes_o, n);
@@ -158,7 +165,7 @@ RRTTL_toWire(s_RRTTL* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->rrttl->toWire(*mr->messagerenderer);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -171,7 +178,7 @@ RRTTL_toWire(s_RRTTL* self, PyObject* args) {
 
 PyObject*
 RRTTL_getValue(s_RRTTL* self) {
-    return (Py_BuildValue("I", self->rrttl->getValue()));
+    return (Py_BuildValue("I", self->cppobj->getValue()));
 }
 
 PyObject*
@@ -186,24 +193,24 @@ RRTTL_richcmp(s_RRTTL* self, s_RRTTL* other, int op) {
 
     switch (op) {
     case Py_LT:
-        c = *self->rrttl < *other->rrttl;
+        c = *self->cppobj < *other->cppobj;
         break;
     case Py_LE:
-        c = *self->rrttl < *other->rrttl ||
-            *self->rrttl == *other->rrttl;
+        c = *self->cppobj < *other->cppobj ||
+            *self->cppobj == *other->cppobj;
         break;
     case Py_EQ:
-        c = *self->rrttl == *other->rrttl;
+        c = *self->cppobj == *other->cppobj;
         break;
     case Py_NE:
-        c = *self->rrttl != *other->rrttl;
+        c = *self->cppobj != *other->cppobj;
         break;
     case Py_GT:
-        c = *other->rrttl < *self->rrttl;
+        c = *other->cppobj < *self->cppobj;
         break;
     case Py_GE:
-        c = *other->rrttl < *self->rrttl ||
-            *self->rrttl == *other->rrttl;
+        c = *other->cppobj < *self->cppobj ||
+            *self->cppobj == *other->cppobj;
         break;
     }
     if (c)
@@ -285,6 +292,7 @@ PyTypeObject rrttl_type = {
 };
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_RRTTL(PyObject* mod) {
     // Add the exceptions to the module
@@ -305,6 +313,25 @@ initModulePart_RRTTL(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+PyObject*
+createRRTTLObject(const RRTTL& source) {
+    RRTTLContainer container = PyObject_New(s_RRTTL, &rrttl_type);
+    container.set(new RRTTL(source));
+    return (container.release());
+}
+
+bool
+PyRRTTL_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &rrttl_type));
+}
+
+const RRTTL&
+PyRRTTL_ToRRTTL(const PyObject* rrttl_obj) {
+    const s_RRTTL* rrttl = static_cast<const s_RRTTL*>(rrttl_obj);
+    return (*rrttl->cppobj);
+}
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/rrttl_python.h b/src/lib/dns/python/rrttl_python.h
index 2b77540..ba0f5f5 100644
--- a/src/lib/dns/python/rrttl_python.h
+++ b/src/lib/dns/python/rrttl_python.h
@@ -31,16 +31,34 @@ namespace python {
 extern PyObject* po_InvalidRRTTL;
 extern PyObject* po_IncompleteRRTTL;
 
-// The s_* Class simply covers one instantiation of the object
-class s_RRTTL : public PyObject {
-public:
-    isc::dns::RRTTL* rrttl;
-};
+extern PyTypeObject rrttl_type;
 
+/// This is a simple shortcut to create a python RRTTL object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createRRTTLObject(const RRTTL& source);
 
-extern PyTypeObject rrttl_type;
+/// \brief Checks if the given python object is a RRTTL object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type RRTTL, false otherwise
+bool PyRRTTL_Check(PyObject* obj);
 
-bool initModulePart_RRTTL(PyObject* mod);
+/// \brief Returns a reference to the RRTTL object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type RRTTL; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRRTTL_Check()
+///
+/// \note This is not a copy; if the RRTTL is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rrttl_obj The rrttl object to convert
+const RRTTL& PyRRTTL_ToRRTTL(const PyObject* rrttl_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/rrtype_python.cc b/src/lib/dns/python/rrtype_python.cc
index c1bc25c..6b6fcc8 100644
--- a/src/lib/dns/python/rrtype_python.cc
+++ b/src/lib/dns/python/rrtype_python.cc
@@ -30,6 +30,11 @@ using namespace isc::util;
 using namespace isc::util::python;
 
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_RRType : public PyObject {
+public:
+    const RRType* cppobj;
+};
 
 // General creation and destruction
 int RRType_init(s_RRType* self, PyObject* args);
@@ -185,7 +190,7 @@ RRType_str(PyObject* self) {
 PyObject*
 RRType_toWire(s_RRType* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -199,7 +204,7 @@ RRType_toWire(s_RRType* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->messagerenderer);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -428,6 +433,7 @@ PyTypeObject rrtype_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool
 initModulePart_RRType(PyObject* mod) {
     // Add the exceptions to the module
@@ -448,6 +454,7 @@ initModulePart_RRType(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 PyObject*
 createRRTypeObject(const RRType& source) {
@@ -456,15 +463,14 @@ createRRTypeObject(const RRType& source) {
     return (container.release());
 }
 
-
 bool
 PyRRType_Check(PyObject* obj) {
     return (PyObject_TypeCheck(obj, &rrtype_type));
 }
 
 const RRType&
-PyRRType_ToRRType(PyObject* rrtype_obj) {
-    s_RRType* rrtype = static_cast<s_RRType*>(rrtype_obj);
+PyRRType_ToRRType(const PyObject* rrtype_obj) {
+    const s_RRType* rrtype = static_cast<const s_RRType*>(rrtype_obj);
     return (*rrtype->cppobj);
 }
 
diff --git a/src/lib/dns/python/rrtype_python.h b/src/lib/dns/python/rrtype_python.h
index 5a69e04..c251d9e 100644
--- a/src/lib/dns/python/rrtype_python.h
+++ b/src/lib/dns/python/rrtype_python.h
@@ -31,17 +31,8 @@ namespace python {
 extern PyObject* po_InvalidRRType;
 extern PyObject* po_IncompleteRRType;
 
-// The s_* Class simply covers one instantiation of the object
-class s_RRType : public PyObject {
-public:
-    const RRType* cppobj;
-};
-
-
 extern PyTypeObject rrtype_type;
 
-bool initModulePart_RRType(PyObject* mod);
-
 /// This is a simple shortcut to create a python RRType object (in the
 /// form of a pointer to PyObject) with minimal exception safety.
 /// On success, it returns a valid pointer to PyObject with a reference
@@ -67,7 +58,7 @@ bool PyRRType_Check(PyObject* obj);
 /// may be destroyed, the caller must copy it itself.
 ///
 /// \param rrtype_obj The rrtype object to convert
-const RRType& PyRRType_ToRRType(PyObject* rrtype_obj);
+const RRType& PyRRType_ToRRType(const PyObject* rrtype_obj);
 
 
 } // namespace python
diff --git a/src/lib/dns/python/tsig_python.cc b/src/lib/dns/python/tsig_python.cc
index db93a08..9cc596e 100644
--- a/src/lib/dns/python/tsig_python.cc
+++ b/src/lib/dns/python/tsig_python.cc
@@ -48,12 +48,14 @@ using namespace isc::dns::python;
 //
 // TSIGContext
 //
-
-// Trivial constructor.
-s_TSIGContext::s_TSIGContext() : cppobj(NULL) {
-}
-
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGContext : public PyObject {
+public:
+    s_TSIGContext() : cppobj(NULL) {};
+    TSIGContext* cppobj;
+};
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIGContext, TSIGContext> TSIGContextContainer;
 
@@ -101,23 +103,23 @@ int
 TSIGContext_init(s_TSIGContext* self, PyObject* args) {
     try {
         // "From key" constructor
-        const s_TSIGKey* tsigkey_obj;
+        const PyObject* tsigkey_obj;
         if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey_obj)) {
-            self->cppobj = new TSIGContext(*tsigkey_obj->cppobj);
+            self->cppobj = new TSIGContext(PyTSIGKey_ToTSIGKey(tsigkey_obj));
             return (0);
         }
 
         // "From key param + keyring" constructor
         PyErr_Clear();
-        const s_Name* keyname_obj;
-        const s_Name* algname_obj;
-        const s_TSIGKeyRing* keyring_obj;
+        const PyObject* keyname_obj;
+        const PyObject* algname_obj;
+        const PyObject* keyring_obj;
         if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &keyname_obj,
                              &name_type, &algname_obj, &tsigkeyring_type,
                              &keyring_obj)) {
-            self->cppobj = new TSIGContext(*keyname_obj->cppobj,
-                                           *algname_obj->cppobj,
-                                           *keyring_obj->cppobj);
+            self->cppobj = new TSIGContext(PyName_ToName(keyname_obj),
+                                           PyName_ToName(algname_obj),
+                                           PyTSIGKeyRing_ToTSIGKeyRing(keyring_obj));
             return (0);
         }
     } catch (const exception& ex) {
@@ -205,13 +207,13 @@ PyObject*
 TSIGContext_verify(s_TSIGContext* self, PyObject* args) {
     const char* data;
     Py_ssize_t data_len;
-    s_TSIGRecord* py_record;
+    PyObject* py_record;
     PyObject* py_maybe_none;
-    TSIGRecord* record;
+    const TSIGRecord* record;
 
     if (PyArg_ParseTuple(args, "O!y#", &tsigrecord_type, &py_record,
                          &data, &data_len)) {
-        record = py_record->cppobj;
+        record = &PyTSIGRecord_ToTSIGRecord(py_record);
     } else if (PyArg_ParseTuple(args, "Oy#", &py_maybe_none, &data,
                                 &data_len)) {
         record = NULL;
@@ -264,7 +266,7 @@ PyTypeObject tsigcontext_type = {
     NULL,                               // tp_as_number
     NULL,                               // tp_as_sequence
     NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
+    NULL,                               // tp_hash
     NULL,                               // tp_call
     NULL,                               // tp_str
     NULL,                               // tp_getattro
@@ -308,6 +310,7 @@ PyTypeObject tsigcontext_type = {
 };
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_TSIGContext(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -359,6 +362,19 @@ initModulePart_TSIGContext(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+bool
+PyTSIGContext_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigcontext_type));
+}
+
+TSIGContext&
+PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj) {
+    s_TSIGContext* tsigcontext = static_cast<s_TSIGContext*>(tsigcontext_obj);
+    return (*tsigcontext->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/tsig_python.h b/src/lib/dns/python/tsig_python.h
index 1985c82..9be92bb 100644
--- a/src/lib/dns/python/tsig_python.h
+++ b/src/lib/dns/python/tsig_python.h
@@ -23,19 +23,29 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIGContext : public PyObject {
-public:
-    s_TSIGContext();
-    TSIGContext* cppobj;
-};
-
 extern PyTypeObject tsigcontext_type;
 
 // Class specific exceptions
 extern PyObject* po_TSIGContextError;
 
-bool initModulePart_TSIGContext(PyObject* mod);
+/// \brief Checks if the given python object is a TSIGContext object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGContext, false otherwise
+bool PyTSIGContext_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGContext object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGContext; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGContext_Check()
+///
+/// \note This is not a copy; if the TSIGContext is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsigcontext_obj The tsigcontext object to convert
+TSIGContext& PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj);
+
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/tsig_rdata_python.cc b/src/lib/dns/python/tsig_rdata_python.cc
index ebaa0ca..2a32be8 100644
--- a/src/lib/dns/python/tsig_rdata_python.cc
+++ b/src/lib/dns/python/tsig_rdata_python.cc
@@ -45,11 +45,15 @@ using namespace isc::dns::python;
 // TSIG RDATA
 //
 
-// Trivial constructor.
-s_TSIG::s_TSIG() : cppobj(NULL) {
-}
-
 namespace {
+    // The s_* Class simply covers one instantiation of the object
+class s_TSIG : public PyObject {
+public:
+    s_TSIG() : cppobj(NULL) {};
+    const rdata::any::TSIG* cppobj;
+};
+
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIG, any::TSIG> TSIGContainer;
 
@@ -236,7 +240,7 @@ TSIG_toWire(const s_TSIG* const self, PyObject* args) {
                 self, args));
 }
 
-PyObject* 
+PyObject*
 TSIG_richcmp(const s_TSIG* const self,
                    const s_TSIG* const other,
                    const int op)
@@ -303,7 +307,7 @@ PyTypeObject tsig_type = {
     NULL,                               // tp_as_number
     NULL,                               // tp_as_sequence
     NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
+    NULL,                               // tp_hash
     NULL,                               // tp_call
     TSIG_str,                       // tp_str
     NULL,                               // tp_getattro
@@ -342,6 +346,7 @@ PyTypeObject tsig_type = {
 };
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_TSIG(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -358,6 +363,7 @@ initModulePart_TSIG(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 PyObject*
 createTSIGObject(const any::TSIG& source) {
@@ -365,6 +371,18 @@ createTSIGObject(const any::TSIG& source) {
     container.set(new any::TSIG(source));
     return (container.release());
 }
+
+bool
+PyTSIG_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsig_type));
+}
+
+const any::TSIG&
+PyTSIG_ToTSIG(const PyObject* tsig_obj) {
+    const s_TSIG* tsig = static_cast<const s_TSIG*>(tsig_obj);
+    return (*tsig->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/tsig_rdata_python.h b/src/lib/dns/python/tsig_rdata_python.h
index e5e0c6c..cb39317 100644
--- a/src/lib/dns/python/tsig_rdata_python.h
+++ b/src/lib/dns/python/tsig_rdata_python.h
@@ -27,17 +27,8 @@ class TSIG;
 
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIG : public PyObject {
-public:
-    s_TSIG();
-    const rdata::any::TSIG* cppobj;
-};
-
 extern PyTypeObject tsig_type;
 
-bool initModulePart_TSIG(PyObject* mod);
-
 /// This is A simple shortcut to create a python TSIG object (in the
 /// form of a pointer to PyObject) with minimal exception safety.
 /// On success, it returns a valid pointer to PyObject with a reference
@@ -47,6 +38,24 @@ bool initModulePart_TSIG(PyObject* mod);
 /// followed by necessary setup for python exception.
 PyObject* createTSIGObject(const rdata::any::TSIG& source);
 
+/// \brief Checks if the given python object is a TSIG object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIG, false otherwise
+bool PyTSIG_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIG object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIG; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIG_Check()
+///
+/// \note This is not a copy; if the TSIG is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsig_obj The tsig object to convert
+const rdata::any::TSIG& PyTSIG_ToTSIG(const PyObject* tsig_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/tsigerror_python.cc b/src/lib/dns/python/tsigerror_python.cc
index 0ad4716..a3ff402 100644
--- a/src/lib/dns/python/tsigerror_python.cc
+++ b/src/lib/dns/python/tsigerror_python.cc
@@ -42,14 +42,17 @@ using namespace isc::dns::python;
 // TSIGError
 //
 
-// Trivial constructor.
-s_TSIGError::s_TSIGError() : cppobj(NULL) {
-}
-
 // Import pydoc text
 #include "tsigerror_python_inc.cc"
 
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGError : public PyObject {
+public:
+    s_TSIGError() : cppobj(NULL) {};
+    const TSIGError* cppobj;
+};
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIGError, TSIGError> TSIGErrorContainer;
 
@@ -107,9 +110,9 @@ TSIGError_init(s_TSIGError* self, PyObject* args) {
 
         // Constructor from Rcode
         PyErr_Clear();
-        s_Rcode* py_rcode;
+        PyObject* py_rcode;
         if (PyArg_ParseTuple(args, "O!", &rcode_type, &py_rcode)) {
-            self->cppobj = new TSIGError(*py_rcode->cppobj);
+            self->cppobj = new TSIGError(PyRcode_ToRcode(py_rcode));
             return (0);
         }
     } catch (const isc::OutOfRange& ex) {
@@ -172,13 +175,8 @@ TSIGError_str(PyObject* self) {
 
 PyObject*
 TSIGError_toRcode(const s_TSIGError* const self) {
-    typedef CPPPyObjectContainer<s_Rcode, Rcode> RcodePyObjectContainer;
-
     try {
-        RcodePyObjectContainer rcode_container(PyObject_New(s_Rcode,
-                                                            &rcode_type));
-        rcode_container.set(new Rcode(self->cppobj->toRcode()));
-        return (rcode_container.release());
+        return (createRcodeObject(self->cppobj->toRcode()));
     } catch (const exception& ex) {
         const string ex_what =
             "Failed to convert TSIGError to Rcode: " + string(ex.what());
@@ -190,7 +188,7 @@ TSIGError_toRcode(const s_TSIGError* const self) {
     return (NULL);
 }
 
-PyObject* 
+PyObject*
 TSIGError_richcmp(const s_TSIGError* const self,
                    const s_TSIGError* const other,
                    const int op)
@@ -252,7 +250,7 @@ PyTypeObject tsigerror_type = {
     NULL,                               // tp_as_number
     NULL,                               // tp_as_sequence
     NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
+    NULL,                               // tp_hash
     NULL,                               // tp_call
     // THIS MAY HAVE TO BE CHANGED TO NULL:
     TSIGError_str,                       // tp_str
@@ -300,6 +298,7 @@ installTSIGErrorConstant(const char* name, const TSIGError& val) {
 }
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_TSIGError(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -358,6 +357,7 @@ initModulePart_TSIGError(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 PyObject*
 createTSIGErrorObject(const TSIGError& source) {
diff --git a/src/lib/dns/python/tsigerror_python.h b/src/lib/dns/python/tsigerror_python.h
index 9cb1b5d..14391ff 100644
--- a/src/lib/dns/python/tsigerror_python.h
+++ b/src/lib/dns/python/tsigerror_python.h
@@ -23,17 +23,8 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIGError : public PyObject {
-public:
-    s_TSIGError();
-    const TSIGError* cppobj;
-};
-
 extern PyTypeObject tsigerror_type;
 
-bool initModulePart_TSIGError(PyObject* mod);
-
 /// This is A simple shortcut to create a python TSIGError object (in the
 /// form of a pointer to PyObject) with minimal exception safety.
 /// On success, it returns a valid pointer to PyObject with a reference
@@ -42,6 +33,7 @@ bool initModulePart_TSIGError(PyObject* mod);
 /// This function is expected to be called with in a try block
 /// followed by necessary setup for python exception.
 PyObject* createTSIGErrorObject(const TSIGError& source);
+
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/tsigkey_python.cc b/src/lib/dns/python/tsigkey_python.cc
index f0906cb..8962bca 100644
--- a/src/lib/dns/python/tsigkey_python.cc
+++ b/src/lib/dns/python/tsigkey_python.cc
@@ -43,11 +43,14 @@ using namespace isc::dns::python;
 // TSIGKey
 //
 
+namespace {
 // The s_* Class simply covers one instantiation of the object
+class s_TSIGKey : public PyObject {
+public:
+    s_TSIGKey() : cppobj(NULL) {};
+    TSIGKey* cppobj;
+};
 
-s_TSIGKey::s_TSIGKey() : cppobj(NULL) {}
-
-namespace {
 //
 // We declare the functions here, the definitions are below
 // the type definition of the object, since both can use the other
@@ -96,8 +99,8 @@ TSIGKey_init(s_TSIGKey* self, PyObject* args) {
         }
 
         PyErr_Clear();
-        const s_Name* key_name;
-        const s_Name* algorithm_name;
+        const PyObject* key_name;
+        const PyObject* algorithm_name;
         PyObject* bytes_obj;
         const char* secret;
         Py_ssize_t secret_len;
@@ -107,8 +110,8 @@ TSIGKey_init(s_TSIGKey* self, PyObject* args) {
             if (secret_len == 0) {
                 secret = NULL;
             }
-            self->cppobj = new TSIGKey(*key_name->cppobj,
-                                       *algorithm_name->cppobj,
+            self->cppobj = new TSIGKey(PyName_ToName(key_name),
+                                       PyName_ToName(algorithm_name),
                                        secret, secret_len);
             return (0);
         }
@@ -196,7 +199,7 @@ PyTypeObject tsigkey_type = {
     NULL,                               // tp_as_number
     NULL,                               // tp_as_sequence
     NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
+    NULL,                               // tp_hash
     NULL,                               // tp_call
     NULL,                               // tp_str
     NULL,                               // tp_getattro
@@ -234,6 +237,7 @@ PyTypeObject tsigkey_type = {
 };
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_TSIGKey(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -276,6 +280,19 @@ initModulePart_TSIGKey(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+bool
+PyTSIGKey_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigkey_type));
+}
+
+const TSIGKey&
+PyTSIGKey_ToTSIGKey(const PyObject* tsigkey_obj) {
+    const s_TSIGKey* tsigkey = static_cast<const s_TSIGKey*>(tsigkey_obj);
+    return (*tsigkey->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc
@@ -291,9 +308,13 @@ initModulePart_TSIGKey(PyObject* mod) {
 
 // The s_* Class simply covers one instantiation of the object
 
-s_TSIGKeyRing::s_TSIGKeyRing() : cppobj(NULL) {}
-
 namespace {
+class s_TSIGKeyRing : public PyObject {
+public:
+    s_TSIGKeyRing() : cppobj(NULL) {};
+    TSIGKeyRing* cppobj;
+};
+
 //
 // We declare the functions here, the definitions are below
 // the type definition of the object, since both can use the other
@@ -329,7 +350,7 @@ TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args) {
                         "Invalid arguments to TSIGKeyRing constructor");
         return (-1);
     }
-    
+
     self->cppobj = new(nothrow) TSIGKeyRing();
     if (self->cppobj == NULL) {
         PyErr_SetString(po_IscException, "Allocating TSIGKeyRing failed");
@@ -354,7 +375,7 @@ TSIGKeyRing_size(const s_TSIGKeyRing* const self) {
 PyObject*
 TSIGKeyRing_add(const s_TSIGKeyRing* const self, PyObject* args) {
     s_TSIGKey* tsigkey;
-    
+
     if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey)) {
         try {
             const TSIGKeyRing::Result result =
@@ -374,11 +395,11 @@ TSIGKeyRing_add(const s_TSIGKeyRing* const self, PyObject* args) {
 
 PyObject*
 TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
-    s_Name* key_name;
+    PyObject* key_name;
 
     if (PyArg_ParseTuple(args, "O!", &name_type, &key_name)) {
         const TSIGKeyRing::Result result =
-            self->cppobj->remove(*key_name->cppobj);
+            self->cppobj->remove(PyName_ToName(key_name));
         return (Py_BuildValue("I", result));
     }
 
@@ -390,13 +411,14 @@ TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
 
 PyObject*
 TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args) {
-    s_Name* key_name;
-    s_Name* algorithm_name;
+    PyObject* key_name;
+    PyObject* algorithm_name;
 
     if (PyArg_ParseTuple(args, "O!O!", &name_type, &key_name,
                          &name_type, &algorithm_name)) {
         const TSIGKeyRing::FindResult result =
-            self->cppobj->find(*key_name->cppobj, *algorithm_name->cppobj);
+            self->cppobj->find(PyName_ToName(key_name),
+                               PyName_ToName(algorithm_name));
         if (result.key != NULL) {
             s_TSIGKey* key = PyObject_New(s_TSIGKey, &tsigkey_type);
             if (key == NULL) {
@@ -436,7 +458,7 @@ PyTypeObject tsigkeyring_type = {
     NULL,                               // tp_as_number
     NULL,                               // tp_as_sequence
     NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
+    NULL,                               // tp_hash
     NULL,                               // tp_call
     NULL,                               // tp_str
     NULL,                               // tp_getattro
@@ -472,6 +494,7 @@ PyTypeObject tsigkeyring_type = {
     0                                   // tp_version_tag
 };
 
+namespace internal {
 bool
 initModulePart_TSIGKeyRing(PyObject* mod) {
     if (PyType_Ready(&tsigkeyring_type) < 0) {
@@ -494,6 +517,20 @@ initModulePart_TSIGKeyRing(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
+
+bool
+PyTSIGKeyRing_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigkeyring_type));
+}
+
+const TSIGKeyRing&
+PyTSIGKeyRing_ToTSIGKeyRing(const PyObject* tsigkeyring_obj) {
+    const s_TSIGKeyRing* tsigkeyring =
+        static_cast<const s_TSIGKeyRing*>(tsigkeyring_obj);
+    return (*tsigkeyring->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/tsigkey_python.h b/src/lib/dns/python/tsigkey_python.h
index 980edc5..a634f4f 100644
--- a/src/lib/dns/python/tsigkey_python.h
+++ b/src/lib/dns/python/tsigkey_python.h
@@ -23,24 +23,44 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIGKey : public PyObject {
-public:
-    s_TSIGKey();
-    TSIGKey* cppobj;
-};
-
-class s_TSIGKeyRing : public PyObject {
-public:
-    s_TSIGKeyRing();
-    TSIGKeyRing* cppobj;
-};
-
 extern PyTypeObject tsigkey_type;
 extern PyTypeObject tsigkeyring_type;
 
-bool initModulePart_TSIGKey(PyObject* mod);
-bool initModulePart_TSIGKeyRing(PyObject* mod);
+/// \brief Checks if the given python object is a TSIGKey object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGKey, false otherwise
+bool PyTSIGKey_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGKey object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGKey; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGKey_Check()
+///
+/// \note This is not a copy; if the TSIGKey is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsigkey_obj The tsigkey object to convert
+const TSIGKey& PyTSIGKey_ToTSIGKey(const PyObject* tsigkey_obj);
+
+/// \brief Checks if the given python object is a TSIGKeyRing object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGKeyRing, false otherwise
+bool PyTSIGKeyRing_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGKeyRing object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGKeyRing; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGKeyRing_Check()
+///
+/// \note This is not a copy; if the TSIGKeyRing is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsigkeyring_obj The tsigkeyring object to convert
+const TSIGKeyRing& PyTSIGKeyRing_ToTSIGKeyRing(const PyObject* tsigkeyring_obj);
 
 } // namespace python
 } // namespace dns
diff --git a/src/lib/dns/python/tsigrecord_python.cc b/src/lib/dns/python/tsigrecord_python.cc
index 8a78b5e..f51e5db 100644
--- a/src/lib/dns/python/tsigrecord_python.cc
+++ b/src/lib/dns/python/tsigrecord_python.cc
@@ -45,10 +45,15 @@ using namespace isc::dns::python;
 //
 
 // Trivial constructor.
-s_TSIGRecord::s_TSIGRecord() : cppobj(NULL) {
-}
 
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGRecord : public PyObject {
+public:
+    s_TSIGRecord() : cppobj(NULL) {};
+    TSIGRecord* cppobj;
+};
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIGRecord, TSIGRecord> TSIGRecordContainer;
 
@@ -102,11 +107,12 @@ PyMethodDef TSIGRecord_methods[] = {
 int
 TSIGRecord_init(s_TSIGRecord* self, PyObject* args) {
     try {
-        const s_Name* py_name;
-        const s_TSIG* py_tsig;
+        const PyObject* py_name;
+        const PyObject* py_tsig;
         if (PyArg_ParseTuple(args, "O!O!", &name_type, &py_name,
                              &tsig_type, &py_tsig)) {
-            self->cppobj = new TSIGRecord(*py_name->cppobj, *py_tsig->cppobj);
+            self->cppobj = new TSIGRecord(PyName_ToName(py_name),
+                                          PyTSIG_ToTSIG(py_tsig));
             return (0);
         }
     } catch (const exception& ex) {
@@ -226,7 +232,7 @@ PyTypeObject tsigrecord_type = {
     NULL,                               // tp_as_number
     NULL,                               // tp_as_sequence
     NULL,                               // tp_as_mapping
-    NULL,                               // tp_hash 
+    NULL,                               // tp_hash
     NULL,                               // tp_call
     TSIGRecord_str,                       // tp_str
     NULL,                               // tp_getattro
@@ -263,6 +269,7 @@ PyTypeObject tsigrecord_type = {
 };
 
 // Module Initialization, all statics are initialized here
+namespace internal {
 bool
 initModulePart_TSIGRecord(PyObject* mod) {
     // We initialize the static description object with PyType_Ready(),
@@ -298,6 +305,7 @@ initModulePart_TSIGRecord(PyObject* mod) {
 
     return (true);
 }
+} // end namespace internal
 
 PyObject*
 createTSIGRecordObject(const TSIGRecord& source) {
@@ -306,6 +314,19 @@ createTSIGRecordObject(const TSIGRecord& source) {
     container.set(new TSIGRecord(source));
     return (container.release());
 }
+
+bool
+PyTSIGRecord_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigrecord_type));
+}
+
+const TSIGRecord&
+PyTSIGRecord_ToTSIGRecord(PyObject* tsigrecord_obj) {
+    s_TSIGRecord* tsigrecord = static_cast<s_TSIGRecord*>(tsigrecord_obj);
+    return (*tsigrecord->cppobj);
+}
+
+
 } // namespace python
 } // namespace dns
 } // namespace isc
diff --git a/src/lib/dns/python/tsigrecord_python.h b/src/lib/dns/python/tsigrecord_python.h
index ef9669b..d968c8e 100644
--- a/src/lib/dns/python/tsigrecord_python.h
+++ b/src/lib/dns/python/tsigrecord_python.h
@@ -23,17 +23,8 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIGRecord : public PyObject {
-public:
-    s_TSIGRecord();
-    TSIGRecord* cppobj;
-};
-
 extern PyTypeObject tsigrecord_type;
 
-bool initModulePart_TSIGRecord(PyObject* mod);
-
 /// This is A simple shortcut to create a python TSIGRecord object (in the
 /// form of a pointer to PyObject) with minimal exception safety.
 /// On success, it returns a valid pointer to PyObject with a reference
@@ -43,6 +34,24 @@ bool initModulePart_TSIGRecord(PyObject* mod);
 /// followed by necessary setup for python exception.
 PyObject* createTSIGRecordObject(const TSIGRecord& source);
 
+/// \brief Checks if the given python object is a TSIGRecord object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGRecord, false otherwise
+bool PyTSIGRecord_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGRecord object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGRecord; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGRecord_Check()
+///
+/// \note This is not a copy; if the TSIGRecord is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rrtype_obj The rrtype object to convert
+const TSIGRecord& PyTSIGRecord_ToTSIGRecord(PyObject* tsigrecord_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc




More information about the bind10-changes mailing list