Browse Source

[trac756] Adding messages to the dictionary

Michal 'vorner' Vaner 14 years ago
parent
commit
c9abaf3a9e

+ 2 - 2
src/lib/log/compiler/message.cc

@@ -266,12 +266,12 @@ writePythonFile(const string& file, MessageDictionary& dictionary) {
         "# File created from " << message_file.fullName() << " on " <<
             currentTime() << "\n" <<
         "\n" <<
-        "import isc.log.message\n" <<
+        "import isc.log\n" <<
         "\n";
 
     vector<string> idents(sortedIdentifiers(dictionary));
     BOOST_FOREACH(const string& ident, idents) {
-        pyfile << ident << " = isc.log.message.create(\"" <<
+        pyfile << ident << " = isc.log.create_message(\"" <<
             ident << "\", \"" << quoteString(dictionary.getText(ident)) <<
             "\")\n";
     }

+ 1 - 1
src/lib/python/isc/log/Makefile.am

@@ -6,7 +6,7 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 pythondir = $(pyexecdir)/isc
 python_LTLIBRARIES = log.la
-log_la_SOURCES = main.cc
+log_la_SOURCES = log.cc
 
 log_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
 log_la_LDFLAGS = $(PYTHON_LDFLAGS)

+ 170 - 0
src/lib/python/isc/log/log.cc

@@ -0,0 +1,170 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <structmember.h>
+
+#include <config.h>
+
+#include <log/message_dictionary.h>
+
+using namespace isc::log;
+
+namespace {
+
+
+// This is for testing only. The real module will have it always set as
+// NULL and will use the global dictionary.
+MessageDictionary* testDictionary = NULL;
+
+PyObject*
+setTestDictionary(PyObject*, PyObject* args) {
+    PyObject* enableO;
+    // The API doesn't seem to provide conversion to bool,
+    // so we do it little bit manually
+    if (!PyArg_ParseTuple(args, "O", &enableO)) {
+        return (NULL);
+    }
+    int enableI(PyObject_IsTrue(enableO));
+    if (enableI == -1) {
+        return (NULL);
+    }
+    bool enable(enableI != 0);
+
+    delete testDictionary;
+    testDictionary = NULL;
+    try {
+        if (enable) {
+            testDictionary = new MessageDictionary;
+        }
+    }
+    catch (const std::exception& e) {
+        PyErr_SetString(PyExc_RuntimeError, e.what());
+        return (NULL);
+    }
+    catch (...) {
+        PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
+        return (NULL);
+    }
+    Py_RETURN_NONE;
+}
+
+PyObject*
+createMessage(PyObject*, PyObject* args) {
+    const char* mid;
+    const char* text;
+    // We parse the strings
+    if (!PyArg_ParseTuple(args, "ss", &mid, &text)) {
+        return (NULL);
+    }
+    PyObject* origMid;
+    // And extract the original representation of the message
+    // ID, so we can return it instead of creating another instance.
+    // This call shouldn't fail if the previous suceeded.
+    if (!PyArg_ParseTuple(args, "Os", &origMid, &text)) {
+        return (NULL);
+    }
+
+    try {
+        MessageDictionary* dict = testDictionary ? testDictionary :
+            &MessageDictionary::globalDictionary();
+
+        // We ignore the result, they will be in some kind of dupe list
+        // if there's a problem
+        dict->add(mid, text);
+    }
+    catch (const std::exception& e) {
+        PyErr_SetString(PyExc_RuntimeError, e.what());
+        return (NULL);
+    }
+    catch (...) {
+        PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
+        return (NULL);
+    }
+
+    // Return the ID
+    Py_INCREF(origMid);
+    return (origMid);
+}
+
+PyObject*
+getMessage(PyObject*, PyObject* args) {
+    const char* mid;
+    if (!PyArg_ParseTuple(args, "s", &mid)) {
+        return (NULL);
+    }
+
+    try {
+        MessageDictionary* dict = testDictionary ? testDictionary :
+            &MessageDictionary::globalDictionary();
+
+        const std::string& result(dict->getText(mid));
+        if (result.empty()) {
+            Py_RETURN_NONE;
+        } else {
+            return (Py_BuildValue("s", result.c_str()));
+        }
+    }
+    catch (const std::exception& e) {
+        PyErr_SetString(PyExc_RuntimeError, e.what());
+        return (NULL);
+    }
+    catch (...) {
+        PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception");
+        return (NULL);
+    }
+}
+
+PyMethodDef methods[] = {
+    {"set_test_dictionary", &setTestDictionary, METH_VARARGS,
+        "Set or unset testing mode for message dictionary. In testing, "
+        "the create_message and get_message functions work on different "
+        "than the logger-global dictionary, not polluting it."},
+    {"create_message", &createMessage, METH_VARARGS,
+        "Creates a new message in the dictionary. You shouldn't need to "
+        "call this directly, it should be called by the generated message "
+        "file. Returns the identifier to be used in logging. The text "
+        "shouldn't be empty."},
+    {"get_message", &getMessage, METH_VARARGS,
+        "Get a message. This function is for testing purposes and you don't "
+        "need to call it. It returns None if the message does not exist."},
+    {NULL, NULL, 0, NULL}
+};
+
+PyModuleDef iscLog = {
+    { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
+    "log",
+    "Python bindings for the classes in the isc::log namespace.\n\n"
+    "These bindings are close match to the C++ API, but they are not complete "
+    "(some parts are not needed) and some are done in more python-like ways.",
+    -1,
+    methods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+}
+
+PyMODINIT_FUNC
+PyInit_log(void) {
+    PyObject* mod = PyModule_Create(&iscLog);
+    if (mod == NULL) {
+        return (NULL);
+    }
+
+    return (mod);
+}

+ 0 - 47
src/lib/python/isc/log/main.cc

@@ -1,47 +0,0 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <structmember.h>
-
-#include <config.h>
-
-namespace {
-
-PyModuleDef iscLog = {
-    { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
-    "log",
-    "Python bindings for the classes in the isc::log namespace.\n\n"
-    "These bindings are close match to the C++ API, but they are not complete "
-    "(some parts are not needed) and some are done in more python-like ways.",
-    -1,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
-
-}
-
-PyMODINIT_FUNC
-PyInit_log(void) {
-    PyObject* mod = PyModule_Create(&iscLog);
-    if (mod == NULL) {
-        return (NULL);
-    }
-
-    return (mod);
-}

+ 17 - 0
src/lib/python/isc/log/tests/log_test.py

@@ -15,4 +15,21 @@
 
 # This tests it can be loaded, nothing more yet
 import isc.log
+import unittest
 
+class LogDict(unittest.TestCase):
+    def setUp(self):
+        # We work on a test dictionary now.
+        isc.log.set_test_dictionary(True)
+    def tearDown(self):
+        # Return to the global dictionary
+        isc.log.set_test_dictionary(False)
+
+    def test_load_msgs(self):
+        # Try loading a message and see it's there, but nothing more
+        self.assertEqual(isc.log.create_message("ID", "Text"), "ID")
+        self.assertEqual(isc.log.get_message("ID"), "Text")
+        self.assertEqual(isc.log.get_message("no-ID"), None)
+
+if __name__ == '__main__':
+    unittest.main()