Browse Source

[1179] exceptions

Jelte Jansen 13 years ago
parent
commit
b6261f09b5

+ 31 - 7
src/lib/python/isc/datasrc/client_python.cc

@@ -27,6 +27,7 @@
 
 #include <datasrc/client.h>
 #include <datasrc/database.h>
+#include <datasrc/data_source.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/iterator.h>
 
@@ -82,12 +83,17 @@ DataSourceClient_FindZone(PyObject* po_self, PyObject* args) {
     s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
     PyObject *name;
     if (PyArg_ParseTuple(args, "O!", &isc::dns::python::name_type, &name)) {
-        DataSourceClient::FindResult find_result(
-            self->cppobj->findZone(isc::dns::python::PyName_ToName(name)));
+        try {
+            DataSourceClient::FindResult find_result(
+                self->cppobj->findZone(isc::dns::python::PyName_ToName(name)));
 
-        result::Result r = find_result.code;
-        ZoneFinderPtr zfp = find_result.zone_finder;
-        return Py_BuildValue("IO", r, createZoneFinderObject(zfp));
+            result::Result r = find_result.code;
+            ZoneFinderPtr zfp = find_result.zone_finder;
+            return Py_BuildValue("IO", r, createZoneFinderObject(zfp));
+        } catch (const std::exception& exc) {
+            PyErr_SetString(getDataSourceException("Error"), exc.what());
+            return (NULL);
+        }
     } else {
         return (NULL);
     }
@@ -98,7 +104,16 @@ DataSourceClient_GetIterator(PyObject* po_self, PyObject* args) {
     s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
     PyObject *name_obj;
     if (PyArg_ParseTuple(args, "O!", &isc::dns::python::name_type, &name_obj)) {
-        return (createZoneIteratorObject(self->cppobj->getIterator(isc::dns::python::PyName_ToName(name_obj))));
+        try {
+            return (createZoneIteratorObject(self->cppobj->getIterator(isc::dns::python::PyName_ToName(name_obj))));
+        } catch (const isc::NotImplemented& ne) {
+            PyErr_SetString(getDataSourceException("NotImplemented"), ne.what());
+        } catch (const DataSourceError& dse) {
+            PyErr_SetString(getDataSourceException("Error"), dse.what());
+        } catch (const std::exception& exc) {
+            PyErr_SetString(getDataSourceException("Error"), exc.what());
+            return (NULL);
+        }
     } else {
         return (NULL);
     }
@@ -111,7 +126,16 @@ DataSourceClient_GetUpdater(PyObject* po_self, PyObject* args) {
     PyObject *replace_obj;
     if (PyArg_ParseTuple(args, "O!O", &isc::dns::python::name_type, &name_obj, &replace_obj) && PyBool_Check(replace_obj)) {
         bool replace = (replace_obj != Py_False);
-        return (createZoneUpdaterObject(self->cppobj->getUpdater(isc::dns::python::PyName_ToName(name_obj), replace)));
+        try {
+            return (createZoneUpdaterObject(self->cppobj->getUpdater(isc::dns::python::PyName_ToName(name_obj), replace)));
+        } catch (const isc::NotImplemented& ne) {
+            PyErr_SetString(getDataSourceException("NotImplemented"), ne.what());
+        } catch (const DataSourceError& dse) {
+            PyErr_SetString(getDataSourceException("Error"), dse.what());
+        } catch (const std::exception& exc) {
+            PyErr_SetString(getDataSourceException("Error"), exc.what());
+            return (NULL);
+        }
     } else {
         return (NULL);
     }

+ 5 - 0
src/lib/python/isc/datasrc/datasrc.cc

@@ -60,6 +60,7 @@ getDataSourceException(const char* ex_name) {
 namespace {
 
 PyObject* po_DataSourceError;
+PyObject* po_NotImplemented;
 
 PyModuleDef iscDataSrc = {
     { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
@@ -108,6 +109,10 @@ PyInit_datasrc(void) {
         po_DataSourceError = PyErr_NewException("isc.datasrc.Error", NULL,
                                                 NULL);
         PyObjectContainer(po_DataSourceError).installToModule(mod, "Error");
+        po_NotImplemented = PyErr_NewException("isc.datasrc.NotImplemented",
+                                               NULL, NULL);
+        PyObjectContainer(po_NotImplemented).installToModule(mod,
+                                                             "NotImplemented");
     } catch (...) {
         Py_DECREF(mod);
         return (NULL);

+ 49 - 39
src/lib/python/isc/datasrc/finder_python.cc

@@ -27,6 +27,7 @@
 
 #include <datasrc/client.h>
 #include <datasrc/database.h>
+#include <datasrc/data_source.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/iterator.h>
 #include <datasrc/zone.h>
@@ -71,19 +72,41 @@ typedef CPPPyObjectContainer<s_ZoneFinder, ZoneFinder> ZoneFinderContainer;
 //
 
 // General creation and destruction
-int ZoneFinder_init(s_ZoneFinder* self, PyObject* args);
-void ZoneFinder_destroy(s_ZoneFinder* self);
+int
+ZoneFinder_init(s_ZoneFinder* self, PyObject* args) {
+    // can't be called directly
+    PyErr_SetString(PyExc_TypeError,
+                    "ZoneFinder cannot be constructed directly");
+
+    return (-1);
+}
+
+void
+ZoneFinder_destroy(s_ZoneFinder* const self) {
+    // cppobj is shared ptr, so no need for explicit delete
+    Py_TYPE(self)->tp_free(self);
+}
 
 // These are the functions we export
 //
 PyObject* ZoneFinder_GetClass(PyObject* po_self, PyObject*) {
     s_ZoneFinder* self = static_cast<s_ZoneFinder*>(po_self);
-    return (isc::dns::python::createRRClassObject(self->cppobj->getClass()));
+    try {
+        return (isc::dns::python::createRRClassObject(self->cppobj->getClass()));
+    } catch (const std::exception& exc) {
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
+    }
 }
 
 PyObject* ZoneFinder_GetOrigin(PyObject* po_self, PyObject*) {
     s_ZoneFinder* self = static_cast<s_ZoneFinder*>(po_self);
-    return (isc::dns::python::createNameObject(self->cppobj->getOrigin()));
+    try {
+        return (isc::dns::python::createNameObject(self->cppobj->getOrigin()));
+    } catch (const std::exception& exc) {
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
+    }
 }
 
 PyObject* ZoneFinder_Find(PyObject* po_self, PyObject* args) {
@@ -95,20 +118,28 @@ PyObject* ZoneFinder_Find(PyObject* po_self, PyObject* args) {
     if (PyArg_ParseTuple(args, "O!O!OI", &isc::dns::python::name_type, &name,
                                          &isc::dns::python::rrtype_type, &rrtype,
                                          &target, &options_int)) {
-        ZoneFinder::FindOptions options = static_cast<ZoneFinder::FindOptions>(options_int);
-        ZoneFinder::FindResult find_result(
-            self->cppobj->find(isc::dns::python::PyName_ToName(name),
-                               isc::dns::python::PyRRType_ToRRType(rrtype),
-                               NULL,
-                               options
-                               ));
-        ZoneFinder::Result r = find_result.code;
-        isc::dns::ConstRRsetPtr rrsp = find_result.rrset;
-        if (rrsp) {
-            return Py_BuildValue("IO", r, isc::dns::python::createRRsetObject(*rrsp));
-        } else {
-            Py_INCREF(Py_None);
-            return Py_BuildValue("IO", r, Py_None);
+        try {
+            ZoneFinder::FindOptions options = static_cast<ZoneFinder::FindOptions>(options_int);
+            ZoneFinder::FindResult find_result(
+                self->cppobj->find(isc::dns::python::PyName_ToName(name),
+                                   isc::dns::python::PyRRType_ToRRType(rrtype),
+                                   NULL,
+                                   options
+                                   ));
+            ZoneFinder::Result r = find_result.code;
+            isc::dns::ConstRRsetPtr rrsp = find_result.rrset;
+            if (rrsp) {
+                return Py_BuildValue("IO", r, isc::dns::python::createRRsetObject(*rrsp));
+            } else {
+                Py_INCREF(Py_None);
+                return Py_BuildValue("IO", r, Py_None);
+            }
+        } catch (const DataSourceError& dse) {
+            PyErr_SetString(getDataSourceException("Error"), dse.what());
+            return (NULL);
+        } catch (const std::exception& exc) {
+            PyErr_SetString(getDataSourceException("Error"), exc.what());
+            return (NULL);
         }
     } else {
         return (NULL);
@@ -132,27 +163,6 @@ PyMethodDef ZoneFinder_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-// This is a template of typical code logic of python class initialization
-// with C++ backend.  You'll need to adjust it according to details of the
-// actual C++ class.
-int
-ZoneFinder_init(s_ZoneFinder* self, PyObject* args) {
-    // can't be called directly
-    PyErr_SetString(PyExc_TypeError,
-                    "ZoneFinder cannot be constructed directly");
-
-    return (-1);
-}
-
-// This is a template of typical code logic of python object destructor.
-// In many cases you can use it without modification, but check that carefully.
-void
-ZoneFinder_destroy(s_ZoneFinder* const self) {
-    //delete self->cppobj;
-    //self->cppobj = NULL;
-    Py_TYPE(self)->tp_free(self);
-}
-
 } // end of unnamed namespace
 
 namespace isc {

+ 22 - 25
src/lib/python/isc/datasrc/iterator_python.cc

@@ -61,6 +61,25 @@ namespace {
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_ZoneIterator, ZoneIterator> ZoneIteratorContainer;
 
+
+// General creation and destruction
+int
+ZoneIterator_init(s_ZoneIterator* self, PyObject* args) {
+    // can't be called directly
+    PyErr_SetString(PyExc_TypeError,
+                    "ZoneIterator cannot be constructed directly");
+
+    return (-1);
+}
+
+// This is a template of typical code logic of python object destructor.
+// In many cases you can use it without modification, but check that carefully.
+void
+ZoneIterator_destroy(s_ZoneIterator* const self) {
+    // cppobj is a shared ptr so no need to delete that
+    Py_TYPE(self)->tp_free(self);
+}
+
 //
 // We declare the functions here, the definitions are below
 // the type definition of the object, since both can use the other
@@ -79,14 +98,12 @@ PyObject* ZoneIterator_GetNextRRset(PyObject* po_self, PyObject*) {
         // We could also simply return None again
         PyErr_SetString(getDataSourceException("Error"), isce.what());
         return (NULL);
+    } catch (const std::exception& exc) {
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
     }
-
 }
 
-// General creation and destruction
-int ZoneIterator_init(s_ZoneIterator* self, PyObject* args);
-void ZoneIterator_destroy(s_ZoneIterator* self);
-
 // These are the functions we export
 //
 
@@ -104,26 +121,6 @@ PyMethodDef ZoneIterator_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-// This is a template of typical code logic of python class initialization
-// with C++ backend.  You'll need to adjust it according to details of the
-// actual C++ class.
-int
-ZoneIterator_init(s_ZoneIterator* self, PyObject* args) {
-    // can't be called directly
-    PyErr_SetString(PyExc_TypeError,
-                    "ZoneIterator cannot be constructed directly");
-
-    return (-1);
-}
-
-// This is a template of typical code logic of python object destructor.
-// In many cases you can use it without modification, but check that carefully.
-void
-ZoneIterator_destroy(s_ZoneIterator* const self) {
-    //delete self->cppobj;
-    //self->cppobj = NULL;
-    Py_TYPE(self)->tp_free(self);
-}
 
 } // end of unnamed namespace
 

+ 10 - 4
src/lib/python/isc/datasrc/tests/datasrc_test.py

@@ -30,7 +30,7 @@ NEW_DB_FILE = TESTDATA_WRITE_PATH + "new_db.sqlite3"
 
 class DataSrcClient(unittest.TestCase):
 
-    def atest_iterate(self):
+    def test_iterate(self):
         dsc = isc.datasrc.DataSourceClient(READ_ZONE_DB_FILE)
 
         # for RRSIGS, the TTL's are currently modified. This test should
@@ -169,8 +169,6 @@ class DataSrcUpdater(unittest.TestCase):
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n", rrset.to_text())
 
         rrset_to_delete = rrset;
-        # can't delete rrset with associated sig
-        rrset_to_delete.remove_rrsig()
 
         result, rrset = finder.find(isc.dns.Name("doesnotexist.example.com"),
                                     isc.dns.RRType.TXT(),
@@ -179,8 +177,13 @@ class DataSrcUpdater(unittest.TestCase):
         self.assertEqual(finder.NXDOMAIN, result)
         self.assertEqual(None, rrset)
 
-
+        # can't delete rrset with associated sig. Abuse that to force an
+        # exception first, then remove the sig, then delete the record
         updater = dsc.get_updater(isc.dns.Name("example.com"), True)
+        self.assertRaises(isc.datasrc.Error, updater.delete_rrset, rrset_to_delete)
+
+        rrset_to_delete.remove_rrsig()
+
         updater.delete_rrset(rrset_to_delete)
         updater.commit()
 
@@ -196,6 +199,9 @@ class DataSrcUpdater(unittest.TestCase):
         updater.add_rrset(rrset_to_delete)
         updater.commit()
 
+        # second commit should throw
+        self.assertRaises(isc.datasrc.Error, updater.commit)
+
         result, rrset = finder.find(isc.dns.Name("www.example.com"),
                                     isc.dns.RRType.A(),
                                     None,

+ 48 - 30
src/lib/python/isc/datasrc/updater_python.cc

@@ -27,6 +27,7 @@
 
 #include <datasrc/client.h>
 #include <datasrc/database.h>
+#include <datasrc/data_source.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/zone.h>
 
@@ -67,8 +68,22 @@ typedef CPPPyObjectContainer<s_ZoneUpdater, ZoneUpdater> ZoneUpdaterContainer;
 //
 
 // General creation and destruction
-int ZoneUpdater_init(s_ZoneUpdater* self, PyObject* args);
-void ZoneUpdater_destroy(s_ZoneUpdater* self);
+int
+ZoneUpdater_init(s_ZoneUpdater* self, PyObject* args) {
+    // can't be called directly
+    PyErr_SetString(PyExc_TypeError,
+                    "ZoneUpdater cannot be constructed directly");
+
+    return (-1);
+}
+
+// This is a template of typical code logic of python object destructor.
+// In many cases you can use it without modification, but check that carefully.
+void
+ZoneUpdater_destroy(s_ZoneUpdater* const self) {
+    // cppobj is a shared ptr so should take care of itself
+    Py_TYPE(self)->tp_free(self);
+}
 
 // These are the functions we export
 //
@@ -77,8 +92,16 @@ PyObject* ZoneUpdater_AddRRset(PyObject* po_self, PyObject* args) {
     s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
     PyObject* rrset_obj;
     if (PyArg_ParseTuple(args, "O!", &isc::dns::python::rrset_type, &rrset_obj)) {
-        self->cppobj->addRRset(isc::dns::python::PyRRset_ToRRset(rrset_obj));
-        Py_RETURN_NONE;
+        try {
+            self->cppobj->addRRset(isc::dns::python::PyRRset_ToRRset(rrset_obj));
+            Py_RETURN_NONE;
+        } catch (const DataSourceError& dse) {
+            PyErr_SetString(getDataSourceException("Error"), dse.what());
+            return (NULL);
+        } catch (const std::exception& exc) {
+            PyErr_SetString(getDataSourceException("Error"), exc.what());
+            return (NULL);
+        }
     } else {
         return (NULL);
     }
@@ -89,8 +112,16 @@ PyObject* ZoneUpdater_DeleteRRset(PyObject* po_self, PyObject* args) {
     s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
     PyObject* rrset_obj;
     if (PyArg_ParseTuple(args, "O!", &isc::dns::python::rrset_type, &rrset_obj)) {
-        self->cppobj->deleteRRset(isc::dns::python::PyRRset_ToRRset(rrset_obj));
-        Py_RETURN_NONE;
+        try {
+            self->cppobj->deleteRRset(isc::dns::python::PyRRset_ToRRset(rrset_obj));
+            Py_RETURN_NONE;
+        } catch (const DataSourceError& dse) {
+            PyErr_SetString(getDataSourceException("Error"), dse.what());
+            return (NULL);
+        } catch (const std::exception& exc) {
+            PyErr_SetString(getDataSourceException("Error"), exc.what());
+            return (NULL);
+        }
     } else {
         return (NULL);
     }
@@ -98,8 +129,16 @@ PyObject* ZoneUpdater_DeleteRRset(PyObject* po_self, PyObject* args) {
 
 PyObject* ZoneUpdater_Commit(PyObject* po_self, PyObject*) {
     s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
-    self->cppobj->commit();
-    Py_RETURN_NONE;
+    try {
+        self->cppobj->commit();
+        Py_RETURN_NONE;
+    } catch (const DataSourceError& dse) {
+        PyErr_SetString(getDataSourceException("Error"), dse.what());
+        return (NULL);
+    } catch (const std::exception& exc) {
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
+    }
 }
 
 
@@ -113,34 +152,13 @@ PyObject* ZoneUpdater_Commit(PyObject* po_self, PyObject*) {
 // 3. Argument type
 // 4. Documentation
 PyMethodDef ZoneUpdater_methods[] = {
-/*    { "get_finder", ZoneUpdater_GetFinder, METH_NOARGS, "TODO" },*/
+/*TODO    { "get_finder", ZoneUpdater_GetFinder, METH_NOARGS, "TODO" },*/
     { "add_rrset", ZoneUpdater_AddRRset, METH_VARARGS, "TODO" },
     { "delete_rrset", ZoneUpdater_DeleteRRset, METH_VARARGS, "TODO" },
     { "commit", ZoneUpdater_Commit, METH_NOARGS, "TODO" },
     { NULL, NULL, 0, NULL }
 };
 
-// This is a template of typical code logic of python class initialization
-// with C++ backend.  You'll need to adjust it according to details of the
-// actual C++ class.
-int
-ZoneUpdater_init(s_ZoneUpdater* self, PyObject* args) {
-    // can't be called directly
-    PyErr_SetString(PyExc_TypeError,
-                    "ZoneUpdater cannot be constructed directly");
-
-    return (-1);
-}
-
-// This is a template of typical code logic of python object destructor.
-// In many cases you can use it without modification, but check that carefully.
-void
-ZoneUpdater_destroy(s_ZoneUpdater* const self) {
-    //delete self->cppobj;
-    //self->cppobj = NULL;
-    Py_TYPE(self)->tp_free(self);
-}
-
 } // end of unnamed namespace
 
 namespace isc {