[glom/boostpythonretry] Actually works.
- From: Murray Cumming <murrayc src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glom/boostpythonretry] Actually works.
- Date: Sun, 7 Feb 2010 22:01:27 +0000 (UTC)
commit 3d85e08c8374dbca8474acc9c939460fbfc375d4
Author: Murray Cumming <murrayc murrayc com>
Date: Sun Feb 7 23:01:11 2010 +0100
Actually works.
.../libglom/python_embed/pygdavalue_conversions.cc | 60 +++++++++++-----
glom/python_embed/glom_python.cc | 71 ++++++++++++--------
2 files changed, 84 insertions(+), 47 deletions(-)
---
diff --git a/glom/libglom/python_embed/pygdavalue_conversions.cc b/glom/libglom/python_embed/pygdavalue_conversions.cc
index 50eaf4c..1fd5c76 100644
--- a/glom/libglom/python_embed/pygdavalue_conversions.cc
+++ b/glom/libglom/python_embed/pygdavalue_conversions.cc
@@ -1,3 +1,9 @@
+#include <Python.h>
+#if PY_VERSION_HEX >= 0x02040000
+# include <datetime.h> /* From Python */
+#endif
+#include "pygdavalue_conversions.h"
+
#include <boost/python.hpp>
#include "pygdavalue_conversions.h"
@@ -16,7 +22,7 @@
* Returns: true for success.
*/
bool
-glom_pygda_value_from_pyobject(GValue *boxed, const boost::python::object& input)
+glom_pygda_value_from_pyobject(GValue* boxed, const boost::python::object& input)
{
/* Use an appropriate gda_value_set_*() function.
We can not know what GValue type is actually wanted, so
@@ -68,38 +74,54 @@ glom_pygda_value_from_pyobject(GValue *boxed, const boost::python::object& input
const bool val = extractor_bool;
g_value_init (boxed, G_TYPE_BOOLEAN);
g_value_set_boolean (boxed, val);
+ return true;
}
-/*
+
#if PY_VERSION_HEX >= 0x02040000
- } else if (PyDateTime_Check (input)) {
+ // We shouldn't need to call PyDateTime_IMPORT again,
+ // after already doing it in libglom_init(),
+ // but PyDate_Check crashes (with valgrind warnings) if we don't.
+ //
+ // Causes a C++ compiler warning, so we use its definition directly.
+ // See http://bugs.python.org/issue7463.
+ // PyDateTime_IMPORT; //A macro, needed to use PyDate_Check(), PyDateTime_Check(), etc.
+ PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_Import((char*)"datetime", (char*)"datetime_CAPI");
+ g_assert(PyDateTimeAPI); //This should have been set by the PyDateTime_IMPORT macro
+
+ //TODO: Find some way to do this with boost::python
+ PyObject* input_c = input.ptr();
+ if (PyDateTime_Check (input_c)) {
GdaTimestamp gda;
- gda.year = PyDateTime_GET_YEAR(input);
- gda.month = PyDateTime_GET_MONTH(input);
- gda.day = PyDateTime_GET_DAY(input);
- gda.hour = PyDateTime_DATE_GET_HOUR(input);
- gda.minute = PyDateTime_DATE_GET_MINUTE(input);
- gda.second = PyDateTime_DATE_GET_SECOND(input);
+ gda.year = PyDateTime_GET_YEAR(input_c);
+ gda.month = PyDateTime_GET_MONTH(input_c);
+ gda.day = PyDateTime_GET_DAY(input_c);
+ gda.hour = PyDateTime_DATE_GET_HOUR(input_c);
+ gda.minute = PyDateTime_DATE_GET_MINUTE(input_c);
+ gda.second = PyDateTime_DATE_GET_SECOND(input_c);
gda.timezone = 0;
gda_value_set_timestamp (boxed, &gda);
- } else if (PyDate_Check (input)) {
+ return true;
+ } else if (PyDate_Check (input_c)) {
GDate *gda = g_date_new_dmy(
- PyDateTime_GET_DAY(input),
- (GDateMonth)PyDateTime_GET_MONTH(input),
- PyDateTime_GET_YEAR(input) );
+ PyDateTime_GET_DAY(input_c),
+ (GDateMonth)PyDateTime_GET_MONTH(input_c),
+ PyDateTime_GET_YEAR(input_c) );
g_value_init (boxed, G_TYPE_DATE);
g_value_set_boxed(boxed, gda);
g_date_free(gda);
- } else if (PyTime_Check (input)) {
+ return true;
+ } else if (PyTime_Check (input_c)) {
GdaTime gda;
- gda.hour = PyDateTime_TIME_GET_HOUR(input);
- gda.minute = PyDateTime_TIME_GET_MINUTE(input);
- gda.second = PyDateTime_TIME_GET_SECOND(input);
+ gda.hour = PyDateTime_TIME_GET_HOUR(input_c);
+ gda.minute = PyDateTime_TIME_GET_MINUTE(input_c);
+ gda.second = PyDateTime_TIME_GET_SECOND(input_c);
gda.timezone = 0;
gda_value_set_time (boxed, &gda);
+ return true;
+ }
#endif
-*/
- g_warning("Unhandled python type.");
+ //g_warning("Unhandled python type.");
return false; /* failed. */
}
diff --git a/glom/python_embed/glom_python.cc b/glom/python_embed/glom_python.cc
index ac054c7..a3574a1 100644
--- a/glom/python_embed/glom_python.cc
+++ b/glom/python_embed/glom_python.cc
@@ -126,10 +126,13 @@ void ShowTrace()
if(chrRetval)
{
- Glib::ustring message = _("Python Error: \n");
- message += chrRetval;
- Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR);
- dialog.run();
+ std::cerr << "Glom: Python Error:" << std::endl << chrRetval << std::endl;
+
+ //TODO: Move this to the caller.
+ //Glib::ustring message = _("Python Error: \n");
+ //message += chrRetval;
+ //Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR);
+ //dialog.run();
}
g_free(chrRetval);
}
@@ -199,7 +202,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//We did this in main(): Py_Initialize();
boost::python::object pMain = boost::python::import("__main__");
- boost::python::object pDict(pMain.attr("__dict__")); //TODO: Does boost::python have an equivalent for PyModule_GetDict()?
+ boost::python::object pDict(pMain.attr("__dict__")); //TODO: Does boost::python have an equivalent for PyModule_GetDict()?
//TODO: Complain that this doesn't work:
//boost::python::dict pDict = pMain.attr("__dict__"); //TODO: Does boost::python have an equivalent for PyModule_GetDict()?
if(!pDict)
@@ -267,35 +270,52 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
HandlePythonError();
}
*/
- PyObject* pyValueC = PyRun_String(func_def.c_str(), Py_file_input,
- pDict.ptr(), pDict.ptr());
- if(!pyValueC)
+
+ //TODO: Complain that exec(std::string(something), pMain) doesn't work.
+ boost::python::object pyValue;
+ try
{
- std::cerr << "glom_evaluate_python_function_implementation(): PyRun_String returned null." << std::endl;
+ //TODO: The second dict is optional, and the documentation suggests using pMain as the first argument, but you'll get a
+ //"TypeError: 'module' object does not support item assignment" error if you omit it.
+ //TODO: Make sure that's documented.
+ pyValue = boost::python::exec(func_def.c_str(), pDict, pDict);
+ }
+ catch(const boost::python::error_already_set& ex)
+ {
+ std::cerr << "glom_evaluate_python_function_implementation(): boost::python::exec() threw error_already_set when using text= " << std::endl << func_def << std::endl;
ShowTrace();
return valueResult;
}
- boost::python::handle<> handle(pyValueC);
- boost::python::object pyValue(handle);
- /*
- if(!pyValue) //if(!pyValue.ptr()) is what we meant.
+ if(!pyValue.ptr())
{
- std::cerr << "glom_evaluate_python_function_implementation(): pyValue from PyRun_String() is null. ptr()=" << pyValue.ptr() << std::endl;
+ std::cerr << "glom_evaluate_python_function_implementation(): boost::python::exec failed." << std::endl;
ShowTrace();
return valueResult;
}
- */
//Call the function:
{
- PyObject* pFunc = PyDict_GetItemString(pDict.ptr(), func_name.c_str()); //The result is borrowed, so should not be dereferenced.
- if(!pFunc)
+ boost::python::object pFunc;
+ try
{
+ pFunc = pDict[func_name.c_str()];
+ }
+ catch(const boost::python::error_already_set& ex)
+ {
+ std::cerr << "glom_evaluate_python_function_implementation(): pDict[func_name] threw error_already_set when func_name= " << std::endl << func_name << std::endl;
+ ShowTrace();
+ return valueResult;
+ }
+
+ if(!pFunc.ptr())
+ {
+ std::cerr << "glom_evaluate_python_function_implementation(): pDict[func_name] failed." << std::endl;
HandlePythonError();
+ return valueResult;
}
- if(!PyCallable_Check(pFunc))
+ if(!PyCallable_Check(pFunc.ptr()))
{
HandlePythonError();
g_warning("pFunc is not callable.");
@@ -320,16 +340,12 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//Fill the record's details:
PyGlomRecord_SetFields(pParam, field_values, pDocument, table_name, opened_connection);
- PyObject* pArgs = PyTuple_New(1);
- PyTuple_SetItem(pArgs, 0, (PyObject*)pParam); //The pParam reference is taken by PyTuple_SetItem().
-
//Call the function with this parameter:
- PyObject* pyResult = PyObject_CallObject(pFunc, pArgs);
- Py_DECREF(pArgs);
+ boost::python::object pyResultCpp = pFunc(objRecord);
- if(!pyResult)
+ if(!(pyResultCpp.ptr()))
{
- g_warning("pyResult was null");
+ g_warning("pyResult.ptr() was null");
HandlePythonError();
}
else
@@ -338,7 +354,6 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
bool object_is_gda_value = false;
GValue value = {0, {{0}}};
- boost::python::object pyResultCpp(boost::python::borrowed(pyResult));
const bool test = glom_pygda_value_from_pyobject(&value, pyResultCpp);
if(test)
@@ -359,7 +374,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//For instance, if one of the fields was empty, then the calculation might want to return an empty value,
//instead of returning 0.
- if(pyResult == Py_None) //Direct comparison is possible and recommended, because there is only one pyNone object.
+ if(pyResultCpp == boost::python::object()) //Check if it is PyNone
{
//The result should be an appropriate empty value for this field type:
valueResult = Conversions::get_empty_value(result_type);
@@ -374,7 +389,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
const char* pchResult = 0;
try
{
- pchResult = boost::python::extract<const char*>(pyResult);
+ pchResult = boost::python::extract<const char*>(pyResultCpp);
}
catch(const boost::python::error_already_set& ex)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]