[glom/boostpythonretry] compiles
- From: Murray Cumming <murrayc src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glom/boostpythonretry] compiles
- Date: Mon, 1 Feb 2010 16:11:44 +0000 (UTC)
commit d920fb438346e867e2bc7e24f79cce53ab08fb8e
Author: Murray Cumming <murrayc murrayc com>
Date: Mon Feb 1 17:09:52 2010 +0100
compiles
ChangeLog | 4 +-
Makefile.am | 4 +-
configure.ac | 10 +
glom/libglom/connectionpool.cc | 2 +-
glom/libglom/python_embed/py_glom_record.cc | 233 ++--------
glom/libglom/python_embed/py_glom_record.h | 22 +-
glom/libglom/python_embed/py_glom_related.cc | 135 +-----
glom/libglom/python_embed/py_glom_related.h | 20 +-
glom/libglom/python_embed/py_glom_relatedrecord.cc | 501 +++++++-------------
glom/libglom/python_embed/py_glom_relatedrecord.h | 19 +-
glom/main.cc | 3 +-
glom/python_embed/glom_python.cc | 64 ++--
glom/python_embed/python_module/py_glom_module.cc | 64 +--
13 files changed, 335 insertions(+), 746 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 249499f..7e873a1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -42,12 +42,10 @@
Added a test for BGO bug #607938
-* tests/import/data/albums.csv: Real-world example data used for the CSV
+ * tests/import/data/albums.csv: Real-world example data used for the CSV
import.
-
* tests/import/utils.[h|cc]: Add the possibility to feed a filename into the
ImportTest directly.
-
* tests/import/test_parsing.cc: Test the CSV import of a whole file.
2010-01-27 Michael Hasselmann <michaelh openismus com>
diff --git a/Makefile.am b/Makefile.am
index 0a3375d..d1567b6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -63,7 +63,7 @@ glom_python_embed_python_module_glom_1_14_la_SOURCES = \
glom_python_embed_python_module_glom_1_14_la_LIBADD = \
glom/libglom/libglom-$(GLOM_ABI_VERSION).la \
- $(LIBGLOM_LIBS) $(PYTHON_LIBS)
+ $(LIBGLOM_LIBS) $(PYTHON_LIBS) $(BOOST_PYTHON_LIBS)
if HOST_WIN32
pymod_ldflags = -module -avoid-version -no-undefined -shrext .pyd
@@ -175,7 +175,7 @@ glom_defines = \
-DGLOM_LOCALEDIR=\""$(glom_localedir)"\" \
-DGLOM_PKGDATADIR=\""$(pkgdatadir)"\"
-AM_CPPFLAGS = $(glom_includes) $(GLOM_CFLAGS) $(PYTHON_CPPFLAGS) $(glom_defines)
+AM_CPPFLAGS = $(glom_includes) $(GLOM_CFLAGS) $(PYTHON_CPPFLAGS) $(BOOST_PYTHON_CFLAGS) $(glom_defines)
AM_CFLAGS = $(GLOM_WFLAGS)
AM_CXXFLAGS = $(GLOM_WXXFLAGS)
diff --git a/configure.ac b/configure.ac
index 82fd71d..524c799 100644
--- a/configure.ac
+++ b/configure.ac
@@ -200,6 +200,16 @@ AC_CHECK_FUNCS([strptime])
# For instance: PYTHON=python2.5
MM_CHECK_MODULE_PYTHON
+BOOST_PYTHON_LIBS="-lboost_python-gcc43-mt-1_39.so.1.39."
+#BOOST_PYTHON_LIBS="-lboost_python-mt-py25.so.1.39"
+BOOST_PYTHON_CFLAGS="-I/opt/gnome228/include/boost-1_39"
+AC_SUBST([BOOST_PYTHON_LIBS])
+AC_SUBST([BOOST_PYTHON_CFLAGS])
+
+#These don't work. pyconfig.h can't be found when using python.hpp.
+#AX_PYTHON()
+#AX_BOOST_PYTHON()
+
AC_ARG_ENABLE([update-mime-database],
[AS_HELP_STRING([--disable-update-mime-database],
[do not run the update-mime-database utility
diff --git a/glom/libglom/connectionpool.cc b/glom/libglom/connectionpool.cc
index 949fac9..4548688 100644
--- a/glom/libglom/connectionpool.cc
+++ b/glom/libglom/connectionpool.cc
@@ -535,7 +535,7 @@ bool ConnectionPool::startup(const SlotProgress& slot_progress, bool network_sha
//If we crash while running (unlikely, hopefully), then try to cleanup.
//Comment this out if you want to see the backtrace in a debugger.
- previous_sig_handler = signal(SIGSEGV, &on_linux_signal);
+ //previous_sig_handler = signal(SIGSEGV, &on_linux_signal);
return true;
}
diff --git a/glom/libglom/python_embed/py_glom_record.cc b/glom/libglom/python_embed/py_glom_record.cc
index 659054d..18ab441 100644
--- a/glom/libglom/python_embed/py_glom_record.cc
+++ b/glom/libglom/python_embed/py_glom_record.cc
@@ -34,27 +34,10 @@
namespace Glom
{
-//Allocate a new object:
-//TODO: Why not parse the args here as well as in Record_init()?
-static PyObject *
-Record_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds */)
-{
- PyGlomRecord *self = (PyGlomRecord*)type->tp_alloc(type, 0);
- if(self)
- {
- self->m_related = 0;
-
- self->m_pMap_field_values = new PyGlomRecord::type_map_field_values();
- }
-
- return (PyObject*)self;
-}
-
//Set the object's member data, from the parameters supplied when creating the object:
-static int
-Record_init(PyObject *self, PyObject * /* args */, PyObject * /* kwds */)
+PyGlomRecord::PyGlomRecord()
{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
+ PyGlomRecord *self_record = this;
//static char *kwlist[] = {"test", 0};
@@ -65,18 +48,13 @@ Record_init(PyObject *self, PyObject * /* args */, PyObject * /* kwds */)
if(self_record)
{
self_record->m_related = 0;
-
- if(self_record->m_pMap_field_values == 0)
- self_record->m_pMap_field_values = new PyGlomRecord::type_map_field_values();
+ self_record->m_pMap_field_values = new PyGlomRecord::type_map_field_values();
}
-
- return 0;
}
-static void
-Record_dealloc(PyObject* self)
+PyGlomRecord::~PyGlomRecord()
{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
+ PyGlomRecord *self_record = this;
if(self_record->m_pMap_field_values)
{
@@ -95,55 +73,37 @@ Record_dealloc(PyObject* self)
delete self_record->m_connection;
self_record->m_connection = 0;
}
-
- self_record->ob_type->tp_free((PyObject*)self_record);
}
-static PyObject *
-Record__get_connection(PyObject* self, void* /* closure */)
+boost::python::object PyGlomRecord::get_connection()
{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
+ PyGlomRecord *self_record = this;
if( !self_record->m_connection || !(*(self_record->m_connection)) )
{
- Py_INCREF(Py_None);
- return Py_None;
- }
- else
- {
- return pygobject_new( G_OBJECT( (*(self_record->m_connection))->gobj()) ); //Creates a pygda Connection object.
- }
-}
-
-static PyObject *
-Record__get_table_name(PyObject* self, void* /* closure */)
-{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
+ PyObject* cobject = Py_None;
- if( !self_record->m_table_name || (*(self_record->m_table_name)).empty() )
- {
- Py_INCREF(Py_None);
- return Py_None;
+ //TODO: Is there some way to take the extra reference with boost::python, withour using borrowed()?
+ Py_INCREF(cobject);
+ return boost::python::object( boost::python::borrowed(cobject) );
}
else
{
- const Glib::ustring& the_text = *(self_record->m_table_name); //Avoid that ugly dereference.
- return PyString_FromString(the_text.c_str());
+ PyObject* cobject = pygobject_new( G_OBJECT( (*(self_record->m_connection))->gobj()) ); //Creates a pygda Connection object.
+ return boost::python::object( boost::python::borrowed(cobject) );
}
}
-static PyObject *
-Record__get_related(PyObject* self, void* /* closure */)
+/*
+boost::python::object PyGlomRecord::get_related()
{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
+ PyGlomRecord *self_record = this;
//We initialize it here, so that this work never happens if it's not needed:
if(!(self_record->m_related))
{
//Return a new RelatedRecord:
- PyObject* new_args = PyTuple_New(0);
- self_record->m_related = (PyGlomRelated*)PyObject_Call((PyObject*)PyGlomRelated_GetPyType(), new_args, 0);
- Py_DECREF(new_args);
+ self_record->m_related = new PyGlomRelated();
//Fill it:
Document::type_vec_relationships vecRelationships = self_record->m_document->get_relationships(*(self_record->m_table_name));
@@ -161,158 +121,33 @@ Record__get_related(PyObject* self, void* /* closure */)
}
Py_INCREF(self_record->m_related); //Should we do this?
- return (PyObject*)self_record->m_related;
+ return self_record->m_related;
}
+*/
-
-static PyGetSetDef Record_getseters[] = {
- {(char*)"related",
- (getter)Record__get_related, (setter)0, 0, 0
- },
- {(char*)"connection",
- (getter)Record__get_connection, (setter)0, 0, 0
- },
- {(char*)"table_name",
- (getter)Record__get_table_name, (setter)0, 0, 0
- },
- {0, 0, 0, 0, 0, } // Sentinel
-};
-
-//Adapt to API changes in Python 2.5:
-#if defined(PY_VERSION_HEX) && (PY_VERSION_HEX >= 0x02050000) /* Python 2.5 */
-static Py_ssize_t
-Record_tp_as_mapping_length(PyObject *self)
-{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
- return self_record->m_pMap_field_values->size();
-}
-#else
-static int
-Record_tp_as_mapping_length(PyObject *self)
+long PyGlomRecord::len() const
{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
- return (int)(self_record->m_pMap_field_values->size());
+ if(!m_pMap_field_values)
+ return 0;
+
+ return m_pMap_field_values->size();
}
-#endif
-static PyObject *
-Record_tp_as_mapping_getitem(PyObject *self, PyObject *item)
+boost::python::object PyGlomRecord::getitem(boost::python::object cppitem)
{
- PyGlomRecord *self_record = (PyGlomRecord*)self;
-
- if(PyString_Check(item))
+ const std::string key = boost::python::extract<std::string>(cppitem);
+ if(!m_pMap_field_values)
+ return boost::python::object();
+
+ PyGlomRecord::type_map_field_values::const_iterator iterFind = m_pMap_field_values->find(key);
+ if(iterFind != m_pMap_field_values->end())
{
- const char* pchKey = PyString_AsString(item);
- if(pchKey)
- {
- const Glib::ustring key(pchKey);
- if(self_record && self_record->m_pMap_field_values)
- {
- PyGlomRecord::type_map_field_values::const_iterator iterFind = self_record->m_pMap_field_values->find(key);
- if(iterFind != self_record->m_pMap_field_values->end())
- {
- return glom_pygda_value_as_pyobject(iterFind->second.gobj(), true /* copy */);
- }
- else
- {
- g_warning("Record_tp_as_mapping_getitem(): item not found in m_pMap_field_values. size=%d, item=%s", (int)self_record->m_pMap_field_values->size(), pchKey);
- }
- }
- else
- {
- g_warning("Record_tp_as_mapping_getitem(): self or self->m_pMap_field_values is NULL.");
- }
- }
- else
- {
- g_warning("Record_tp_as_mapping_getitem(): PyString_AsString(item) returned NULL.");
- }
+ PyObject* cResult = glom_pygda_value_as_pyobject(iterFind->second.gobj(), true /* copy */);
+ return boost::python::object(); //TODO_Hack: boost::python::object(cResult);
}
- else
- {
- g_warning("Record_tp_as_mapping_getitem(): PyString_Check(item) failed.");
- }
-
-
- g_warning("Record_tp_as_mapping_getitem(): return null.");
- PyErr_SetString(PyExc_IndexError, "field not found");
- return 0;
-}
-/*
-static int
-Record_tp_as_mapping_setitem(PyGObject *self, PyObject *item, PyObject *value)
-{
- Py_INCREF(Py_None);
- return Py_None;
+ return boost::python::object();
}
-*/
-
-static PyMappingMethods Record_tp_as_mapping = {
- Record_tp_as_mapping_length,
- Record_tp_as_mapping_getitem,
- (objobjargproc)0 /* Record_tp_as_mapping_setitem */
-};
-
-
-static PyTypeObject pyglom_RecordType = {
- PyObject_HEAD_INIT(0)
- 0, /*ob_size*/
- (char*)"glom.Record", /*tp_name*/
- sizeof(PyGlomRecord), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)Record_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- &Record_tp_as_mapping, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- (char*)"Glom objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0 /* Record_methods */, /* tp_methods */
- 0 /* Record_members */, /* tp_members */
- Record_getseters, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)Record_init, /* tp_init */
- 0, /* tp_alloc */
- Record_new, /* tp_new */
- 0, 0, 0, 0, 0, 0, 0, 0, //TODO: or one more 0 if using a newer Python.
-};
-
-PyTypeObject* PyGlomRecord_GetPyType()
-{
- return &pyglom_RecordType;
-}
-
-
-
-/*
-static void Record_HandlePythonError()
-{
- if(PyErr_Occurred())
- PyErr_Print();
-}
-*/
-
void PyGlomRecord_SetFields(PyGlomRecord* self, const PyGlomRecord::type_map_field_values& field_values, Document* document, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
{
diff --git a/glom/libglom/python_embed/py_glom_record.h b/glom/libglom/python_embed/py_glom_record.h
index 8bf072b..cf10f6f 100644
--- a/glom/libglom/python_embed/py_glom_record.h
+++ b/glom/libglom/python_embed/py_glom_record.h
@@ -24,7 +24,7 @@
#define NO_IMPORT_PYGTK //To avoid a multiple definition in pygtk.
#include <pygtk/pygtk.h> //For the PyGObject and PyGBoxed struct definitions.
-#include <Python.h>
+#include <boost/python.hpp>
#include <libglom/document/document.h>
#include <libglom/data_structure/field.h>
@@ -35,11 +35,25 @@ namespace Glom
class PyGlomRelated;
-struct PyGlomRecord
+class PyGlomRecord
{
public:
- PyObject_HEAD
+ PyGlomRecord();
+ ~PyGlomRecord();
+ std::string get_table_name() const;
+
+ //TODO: Use a more specific type somehow?
+ boost::python::object get_connection();
+
+ boost::python::object get_related();
+
+ //[] notation:
+
+ long len() const;
+ boost::python::object getitem(boost::python::object item);
+
+public:
//PyObject* m_fields_dict; //Dictionary (map) of field names (string) to field values (Gnome::Gda::Value).
//PyGObject* m_py_gda_connection; //"derived" from PyObject.
Document* m_document;
@@ -55,8 +69,6 @@ public:
Glib::RefPtr<Gnome::Gda::Connection>* m_connection;
};
-PyTypeObject* PyGlomRecord_GetPyType();
-
void PyGlomRecord_SetFields(PyGlomRecord* self, const PyGlomRecord::type_map_field_values& field_values, Document* document, const Glib::ustring& table_name, const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
} //namespace Glom
diff --git a/glom/libglom/python_embed/py_glom_related.cc b/glom/libglom/python_embed/py_glom_related.cc
index 9d2a45c..5146979 100644
--- a/glom/libglom/python_embed/py_glom_related.cc
+++ b/glom/libglom/python_embed/py_glom_related.cc
@@ -36,12 +36,9 @@
namespace Glom
{
-//Allocate a new object:
-//TODO: Why not parse the args here as well as in Related_init()?
-static PyObject *
-Related_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds */)
+PyGlomRelated::PyGlomRelated()
{
- PyGlomRelated *self = (PyGlomRelated*)type->tp_alloc(type, 0);
+ PyGlomRelated *self = this;
if(self)
{
self->m_record = 0;
@@ -49,34 +46,11 @@ Related_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds */)
self->m_pMap_relationships = new PyGlomRelated::type_map_relationships();
self->m_pMap_relatedrecords = new PyGlomRelated::type_map_relatedrecords();
}
-
- return (PyObject*)self;
-}
-
-//Set the object's member data, from the parameters supplied when creating the object:
-static int
-Related_init(PyObject *self, PyObject* /* args */, PyObject* /* kwds */)
-{
- PyGlomRelated *self_related = (PyGlomRelated*)self;
-
- if(self_related)
- {
- self_related->m_record = 0;
-
- if(self_related->m_pMap_relationships == 0)
- self_related->m_pMap_relationships = new PyGlomRelated::type_map_relationships();
-
- if(self_related->m_pMap_relatedrecords == 0)
- self_related->m_pMap_relatedrecords = new PyGlomRelated::type_map_relatedrecords();
- }
-
- return 0;
}
-static void
-Related_dealloc(PyObject* self)
+PyGlomRelated::~PyGlomRelated()
{
- PyGlomRelated *self_related = (PyGlomRelated*)self;
+ PyGlomRelated *self_related = this;
if(self_related->m_pMap_relationships)
{
@@ -101,32 +75,20 @@ Related_dealloc(PyObject* self)
delete self_related->m_pMap_relatedrecords;
self_related->m_pMap_relatedrecords = 0;
}
-
- self_related->ob_type->tp_free((PyObject*)self);
}
-//Adapt to API changes in Python 2.5:
-#if defined(PY_VERSION_HEX) && (PY_VERSION_HEX >= 0x02050000) /* Python 2.5 */
-static Py_ssize_t
-Related_tp_as_mapping_length(PyObject *self)
+long PyGlomRelated::len() const
{
- PyGlomRelated *self_related = (PyGlomRelated*)self;
+ const PyGlomRelated *self_related = this;
return self_related->m_pMap_relationships->size();
}
-#else
-static int
-Related_tp_as_mapping_length(PyObject *self)
-{
- PyGlomRelated *self_related = (PyGlomRelated*)self;
- return (int)(self_related->m_pMap_relationships->size());
-}
-#endif
-static PyObject *
-Related_tp_as_mapping_getitem(PyObject *self, PyObject *item)
+boost::python::object PyGlomRelated::getitem(boost::python::object cppitem)
{
- PyGlomRelated *self_related = (PyGlomRelated*)self;
+ PyGlomRelated *self_related = this;
+
+ PyObject* item = cppitem.ptr(); //TODO: Just use the C++ object.
if(PyString_Check(item))
{
@@ -141,8 +103,10 @@ Related_tp_as_mapping_getitem(PyObject *self, PyObject *item)
{
//Return a reference to the cached item:
PyGlomRelatedRecord* pyRelatedRecord = iterCacheFind->second;
+
+ PyObject* cobject = (PyObject*)pyRelatedRecord;
Py_INCREF((PyObject*)pyRelatedRecord);
- return (PyObject*)pyRelatedRecord;
+ return boost::python::object(boost::python::borrowed(cobject));
}
else
{
@@ -151,9 +115,7 @@ Related_tp_as_mapping_getitem(PyObject *self, PyObject *item)
if(iterFind != self_related->m_pMap_relationships->end())
{
//Return a new RelatedRecord:
- PyObject* new_args = PyTuple_New(0);
- PyGlomRelatedRecord* pyRelatedRecord = (PyGlomRelatedRecord*)PyObject_Call((PyObject*)PyGlomRelatedRecord_GetPyType(), new_args, 0);
- Py_DECREF(new_args);
+ PyGlomRelatedRecord* pyRelatedRecord = new PyGlomRelatedRecord();
//Fill it.
@@ -183,7 +145,9 @@ Related_tp_as_mapping_getitem(PyObject *self, PyObject *item)
Py_INCREF((PyObject*)pyRelatedRecord); //Dereferenced in _dealloc().
(*(self_related->m_pMap_relatedrecords))[key] = pyRelatedRecord;
- return (PyObject*)pyRelatedRecord; //TODO: pygda_value_as_pyobject(iterFind->second.gobj(), true /* copy */);
+ PyObject* cobject = (PyObject*)pyRelatedRecord;
+ Py_INCREF((PyObject*)cobject);
+ return boost::python::object(boost::python::borrowed(cobject));
}
}
}
@@ -192,72 +156,9 @@ Related_tp_as_mapping_getitem(PyObject *self, PyObject *item)
}
PyErr_SetString(PyExc_IndexError, "relationship not found");
- return 0;
+ return boost::python::object(); //TODO_Hack
}
-/*
-static int
-Related_tp_as_mapping_setitem(PyGObject *self, PyObject *item, PyObject *value)
-{
- Py_INCREF(Py_None);
- return Py_None;
-}
-*/
-
-static PyMappingMethods Related_tp_as_mapping = {
- Related_tp_as_mapping_length,
- Related_tp_as_mapping_getitem,
- (objobjargproc)0 /* Related_tp_as_mapping_setitem */
-};
-
-
-static PyTypeObject pyglom_RelatedType = {
- PyObject_HEAD_INIT(0)
- 0, /*ob_size*/
- (char*)"glom.Related", /*tp_name*/
- sizeof(PyGlomRelated), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)Related_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- &Related_tp_as_mapping, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- (char*)"Glom objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0 /* Related_methods */, /* tp_methods */
- 0 /* Related_members */, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)Related_init, /* tp_init */
- 0, /* tp_alloc */
- Related_new, /* tp_new */
- 0, 0, 0, 0, 0, 0, 0, 0, //TODO: or one more 0 if using a newer Python.
-};
-
-PyTypeObject* PyGlomRelated_GetPyType()
-{
- return &pyglom_RelatedType;
-}
/*
static void Related_HandlePythonError()
diff --git a/glom/libglom/python_embed/py_glom_related.h b/glom/libglom/python_embed/py_glom_related.h
index 1bbaf9f..7190113 100644
--- a/glom/libglom/python_embed/py_glom_related.h
+++ b/glom/libglom/python_embed/py_glom_related.h
@@ -28,24 +28,32 @@ namespace Glom
{
class PyGlomRelatedRecord;
+class PyGlomRecord;
class PyGlomRelated
{
public:
- PyObject_HEAD
+ PyGlomRelated();
+ ~PyGlomRelated();
- PyGlomRecord* m_record; //A reference to the parent record.
+ //[] notation:
+ long len() const;
+ boost::python::object getitem(boost::python::object item);
+
+ friend class PyGlomRecord;
typedef std::map<Glib::ustring, sharedptr<Relationship> > type_map_relationships;
+ typedef std::map<Glib::ustring, PyGlomRelatedRecord*> type_map_relatedrecords;
+
+//TODO: protected:
+ PyGlomRecord* m_record; //A reference to the parent record.
+
+
type_map_relationships* m_pMap_relationships;
- typedef std::map<Glib::ustring, PyGlomRelatedRecord*> type_map_relatedrecords;
type_map_relatedrecords* m_pMap_relatedrecords;
};
-PyTypeObject* PyGlomRelated_GetPyType();
-
-
void PyGlomRelated_SetRelationships(PyGlomRelated* self, const PyGlomRelated::type_map_relationships& relationships);
diff --git a/glom/libglom/python_embed/py_glom_relatedrecord.cc b/glom/libglom/python_embed/py_glom_relatedrecord.cc
index d8edc81..cc4acd3 100644
--- a/glom/libglom/python_embed/py_glom_relatedrecord.cc
+++ b/glom/libglom/python_embed/py_glom_relatedrecord.cc
@@ -37,125 +37,42 @@
namespace Glom
{
-//Allocate a new object:
-//TODO: Why not parse the args here as well as in RelatedRecord_init()?
-static PyObject *
-RelatedRecord_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds */)
+PyGlomRelatedRecord::PyGlomRelatedRecord()
+: m_py_gda_connection(0),
+ m_document(0),
+ m_relationship(0),
+ m_from_key_value_sqlized(0)
{
- PyGlomRelatedRecord *self = (PyGlomRelatedRecord*)type->tp_alloc(type, 0);
- if(self)
- {
- self->m_py_gda_connection = 0;
- self->m_document = 0;
- self->m_relationship = 0;
- self->m_from_key_value_sqlized = 0;
-
- //self->m_record_parent = 0;
-
- self->m_pMap_field_values = new PyGlomRelatedRecord::type_map_field_values();
- }
-
- return (PyObject*)self;
-}
-
-//Set the object's member data, from the parameters supplied when creating the object:
-static int
-RelatedRecord_init(PyGlomRelatedRecord *self, PyObject * /* args */, PyObject * /* kwds */)
-{
- //static char *kwlist[] = {"test", 0};
-
- //if(!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
- // &self->m_test))
- // return -1;
-
- if(self)
- {
- self->m_py_gda_connection = 0;
- self->m_document = 0;
- self->m_relationship = 0;
- self->m_from_key_value_sqlized = 0;
-
- //self->m_record_parent = 0;
-
- if(self->m_pMap_field_values == 0)
- self->m_pMap_field_values = new PyGlomRelatedRecord::type_map_field_values();
- }
-
- return 0;
+ m_pMap_field_values = new PyGlomRelatedRecord::type_map_field_values();
}
-static void
-RelatedRecord_dealloc(PyGlomRelatedRecord* self)
+PyGlomRelatedRecord::~PyGlomRelatedRecord()
{
- if(self->m_pMap_field_values)
+ if(m_pMap_field_values)
{
- delete self->m_pMap_field_values;
- self->m_pMap_field_values = 0;
+ delete m_pMap_field_values;
+ m_pMap_field_values = 0;
}
- if(self->m_relationship)
+ if(m_relationship)
{
- delete self->m_relationship;
- self->m_relationship = 0;
+ delete m_relationship;
+ m_relationship = 0;
}
- if(self->m_from_key_value_sqlized)
+ if(m_from_key_value_sqlized)
{
- delete self->m_from_key_value_sqlized;
- self->m_from_key_value_sqlized = 0;
+ delete m_from_key_value_sqlized;
+ m_from_key_value_sqlized = 0;
}
- if(self->m_py_gda_connection)
+ if(m_py_gda_connection)
{
- Py_XDECREF( (PyObject*)(self->m_py_gda_connection));
- self->m_py_gda_connection = 0;
+ Py_XDECREF( (PyObject*)(m_py_gda_connection));
+ m_py_gda_connection = 0;
}
-
- self->ob_type->tp_free((PyObject*)self);
}
-/*
-static PyObject *
-RelatedRecord__get_fields(PyGlomRelatedRecord *self, void * closure )
-{
- if(self->m_fields_dict)
- {
- Py_INCREF(self->m_fields_dict); //TODO: Should we do this?
- return self->m_fields_dict;
- }
- else
- {
- Py_INCREF(Py_None);
- return Py_None;
- }
-}
-*/
-
-/*
-static PyGetSetDef RelatedRecord_getseters[] = {
- {"fields",
- (getter)RelatedRecord__get_fields, (setter)0, 0, 0
- },
- {0, 0, 0, 0, 0, } // Sentinel
-};
-*/
-
-//Adapt to API changes in Python 2.5:
-#if defined(PY_VERSION_HEX) && (PY_VERSION_HEX >= 0x02050000) /* Python 2.5 */
-static Py_ssize_t
-RelatedRecord_tp_as_mapping_length(PyObject *self)
-{
- PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
- return self_derived->m_pMap_field_values->size();
-}
-#else
-static int
-RelatedRecord_tp_as_mapping_length(PyObject *self)
-{
- PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
- return (int)(self_derived->m_pMap_field_values->size());
-}
-#endif
static void RelatedRecord_HandlePythonError()
{
@@ -163,152 +80,36 @@ static void RelatedRecord_HandlePythonError()
PyErr_Print();
}
-static PyObject *
-RelatedRecord_tp_as_mapping_getitem(PyObject *self, PyObject *item)
-{
- PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
-
- if(PyString_Check(item))
- {
- const char* pchKey = PyString_AsString(item);
- if(pchKey)
- {
- const Glib::ustring field_name(pchKey);
- PyGlomRelatedRecord::type_map_field_values::const_iterator iterFind = self_derived->m_pMap_field_values->find(field_name);
- if(iterFind != self_derived->m_pMap_field_values->end())
- {
- //If the value has already been stored, then just return it again:
- return glom_pygda_value_as_pyobject(iterFind->second.gobj(), true /* copy */);
- }
- else
- {
- const Glib::ustring related_table = (*(self_derived->m_relationship))->get_to_table();
-
- //Check whether the field exists in the table.
- //TODO_Performance: Do this without the useless Field information?
- sharedptr<Field> field = self_derived->m_document->get_field((*(self_derived->m_relationship))->get_to_table(), field_name);
- if(!field)
- g_warning("RelatedRecord_tp_as_mapping_getitem: field %s not found in table %s", field_name.c_str(), (*(self_derived->m_relationship))->get_to_table().c_str());
- else
- {
- //Try to get the value from the database:
- //const Glib::ustring parent_key_name;
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- sharedptr<SharedConnection> sharedconnection = ConnectionPool::get_instance()->connect();
-#else
- std::auto_ptr<ExceptionConnection> conn_error;
- sharedptr<SharedConnection> sharedconnection = ConnectionPool::get_instance()->connect(conn_error);
- // Ignore error, sharedconnection presence is checked below
-#endif
- if(sharedconnection)
- {
- Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
-
- const Glib::ustring related_key_name = (*(self_derived->m_relationship))->get_to_field();
-
- //Do not try to get a value based on a null key value:
- if(!(self_derived->m_from_key_value_sqlized))
- return Py_None;
-
- //Get the single value from the related records:
- Glib::ustring sql_query = "SELECT \"" + related_table + "\".\"" + field_name + "\" FROM \"" + related_table + "\""
- + " WHERE \"" + related_table + "\".\"" + related_key_name + "\" = " + *(self_derived->m_from_key_value_sqlized);
-
- /* TODO: Fix linking problems
- const App_Glom* app = App_Glom::get_application();
- if(app && app->get_show_sql_debug())
- {
- try
- {
- std::cout << "Debug: RelatedRecord_tp_as_mapping_getitem(): " << sql_query << std::endl;
- }
- catch(const Glib::Exception& ex)
- {
- std::cout << "Debug: query string could not be converted to std::cout: " << ex.what() << std::endl;
- }
- }*/
-
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- // TODO: Does this behave well if this throws an exception?
- Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query);
-#else
- std::auto_ptr<Glib::Error> error;
- Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query, Gnome::Gda::STATEMENT_MODEL_RANDOM_ACCESS, error);
- // Ignore error, datamodel return value is checked below
-#endif
- if(datamodel && datamodel->get_n_rows())
- {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
- Gnome::Gda::Value value = datamodel->get_value_at(0, 0);
-#else
- Gnome::Gda::Value value = datamodel->get_value_at(0, 0, error);
-#endif
- //g_warning("RelatedRecord_tp_as_mapping_getitem(): value from datamodel = %s", value.to_string().c_str());
-
- //Cache it, in case it's asked-for again.
- (*(self_derived->m_pMap_field_values))[field_name] = value;
- return glom_pygda_value_as_pyobject(value.gobj(), true /* copy */);
- }
- else if(!datamodel)
- {
- g_warning("RelatedRecord_tp_as_mapping_getitem(): The datamodel was null.");
- ConnectionPool::handle_error_cerr_only();
- RelatedRecord_HandlePythonError();
- }
- else
- {
- g_warning("RelatedRecord_tp_as_mapping_getitem(): No related records exist yet for relationship %s.", (*(self_derived->m_relationship))->get_name().c_str());
- }
- }
- }
- }
- }
- }
-
- g_warning("RelatedRecord_tp_as_mapping_getitem(): return null.");
- PyErr_SetString(PyExc_IndexError, "field not found");
- return 0;
-}
-
-/*
-static int
-RelatedRecord_tp_as_mapping_setitem(PyGObject *self, PyObject *item, PyObject *value)
+long PyGlomRelatedRecord::len() const
{
- Py_INCREF(Py_None);
- return Py_None;
+ if(!m_pMap_field_values)
+ return 0;
+
+ return m_pMap_field_values->size();
}
-*/
-static PyMappingMethods RelatedRecord_tp_as_mapping = {
- RelatedRecord_tp_as_mapping_length,
- RelatedRecord_tp_as_mapping_getitem,
- (objobjargproc)0 /* RelatedRecord_tp_as_mapping_setitem */
-};
-
-static PyObject *
-RelatedRecord_generic_aggregate(PyGlomRelatedRecord* self, PyObject *args, PyObject *kwargs, const Glib::ustring& aggregate)
+boost::python::object PyGlomRelatedRecord::getitem(boost::python::object cppitem)
{
- typedef const char* type_pch;
- static type_pch kwlist[] = { "field_name", 0 };
- PyObject* py_field_name = 0;
-
- if(!PyArg_ParseTupleAndKeywords(args, kwargs, (char*)"O:RelatedRecord.sum", (char**)kwlist, &py_field_name))
- return 0;
-
- if(!(PyString_Check(py_field_name)))
- return 0;
-
- const char* pchKey = PyString_AsString(py_field_name);
- if(pchKey)
+ const std::string field_name = boost::python::extract<std::string>(cppitem);
+ if(!m_pMap_field_values)
+ return boost::python::object();
+
+ PyGlomRelatedRecord::type_map_field_values::const_iterator iterFind = m_pMap_field_values->find(field_name);
+ if(iterFind != m_pMap_field_values->end())
{
- const Glib::ustring field_name(pchKey);
- const Glib::ustring related_table = (*(self->m_relationship))->get_to_table();
+ //If the value has already been stored, then just return it again:
+ PyObject* cResult = glom_pygda_value_as_pyobject(iterFind->second.gobj(), true /* copy */);
+ return boost::python::object(); //TODO_Hack: boost::python::object(cResult);
+ }
+ else
+ {
+ const Glib::ustring related_table = (*m_relationship)->get_to_table();
//Check whether the field exists in the table.
//TODO_Performance: Do this without the useless Field information?
- sharedptr<Field> field = self->m_document->get_field((*(self->m_relationship))->get_to_table(), field_name);
+ sharedptr<Field> field = m_document->get_field((*m_relationship)->get_to_table(), field_name);
if(!field)
- g_warning("RelatedRecord_sum: field %s not found in table %s", field_name.c_str(), (*(self->m_relationship))->get_to_table().c_str());
+ g_warning("RelatedRecord_tp_as_mapping_getitem: field %s not found in table %s", field_name.c_str(), (*m_relationship)->get_to_table().c_str());
else
{
//Try to get the value from the database:
@@ -324,153 +125,171 @@ RelatedRecord_generic_aggregate(PyGlomRelatedRecord* self, PyObject *args, PyObj
{
Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
- const Glib::ustring related_key_name = (*(self->m_relationship))->get_to_field();
+ const Glib::ustring related_key_name = (*m_relationship)->get_to_field();
//Do not try to get a value based on a null key value:
- if(!(self->m_from_key_value_sqlized))
- return Py_None;
+ if(!(m_from_key_value_sqlized))
+ return boost::python::object();
- //Get the aggregate value from the related records:
- const Glib::ustring sql_query = "SELECT " + aggregate + "(\"" + related_table + "\".\"" + field_name + "\") FROM \"" + related_table + "\""
- + " WHERE \"" + related_table + "\".\"" + related_key_name + "\" = " + *(self->m_from_key_value_sqlized);
-
- //std::cout << "PyGlomRelatedRecord: Executing: " << sql_query << std::endl;
+ //Get the single value from the related records:
+ Glib::ustring sql_query = "SELECT \"" + related_table + "\".\"" + field_name + "\" FROM \"" + related_table + "\""
+ + " WHERE \"" + related_table + "\".\"" + related_key_name + "\" = " + *(m_from_key_value_sqlized);
+
+ /* TODO: Fix linking problems
+ const App_Glom* app = App_Glom::get_application();
+ if(app && app->get_show_sql_debug())
+ {
+ try
+ {
+ std::cout << "Debug: RelatedRecord_tp_as_mapping_getitem(): " << sql_query << std::endl;
+ }
+ catch(const Glib::Exception& ex)
+ {
+ std::cout << "Debug: query string could not be converted to std::cout: " << ex.what() << std::endl;
+ }
+ }*/
+
#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ // TODO: Does this behave well if this throws an exception?
Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query);
#else
std::auto_ptr<Glib::Error> error;
- Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query, Gnome::Gda::STATEMENT_MODEL_RANDOM_ACCESS, error);
-
- // Ignore the error: The case that the command execution didn't return
- // a datamodel is handled below.
+ Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query, Gnome::Gda::STATEMENT_MODEL_RANDOM_ACCESS, error);
+ // Ignore error, datamodel return value is checked below
#endif
if(datamodel && datamodel->get_n_rows())
{
-#ifdef GLIBMM_EXCEPTIONS_ENABLED
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
Gnome::Gda::Value value = datamodel->get_value_at(0, 0);
#else
Gnome::Gda::Value value = datamodel->get_value_at(0, 0, error);
-#endif
- //g_warning("RelatedRecord_generic_aggregate(): value from datamodel = %s", value.to_string().c_str());
+#endif
+ //g_warning("RelatedRecord_tp_as_mapping_getitem(): value from datamodel = %s", value.to_string().c_str());
//Cache it, in case it's asked-for again.
- (*(self->m_pMap_field_values))[field_name] = value;
- return glom_pygda_value_as_pyobject(value.gobj(), true /* copy */);
+ (*(m_pMap_field_values))[field_name] = value;
+ PyObject* cResult = glom_pygda_value_as_pyobject(value.gobj(), true /* copy */);
+ return boost::python::object(); //TODO_Hack: boost::python::object(cResult);
}
else if(!datamodel)
{
- g_warning("RelatedRecord_generic_aggregate(): The datamodel was null.");
+ g_warning("RelatedRecord_tp_as_mapping_getitem(): The datamodel was null.");
ConnectionPool::handle_error_cerr_only();
RelatedRecord_HandlePythonError();
}
else
{
- g_warning("RelatedRecord_generic_aggregate(): No related records exist yet for relationship %s.", (*(self->m_relationship))->get_name().c_str());
+ g_warning("RelatedRecord_tp_as_mapping_getitem(): No related records exist yet for relationship %s.", (*m_relationship)->get_name().c_str());
}
}
}
}
- Py_INCREF(Py_None);
- return Py_None;
+ g_warning("RelatedRecord_tp_as_mapping_getitem(): return null.");
+ PyErr_SetString(PyExc_IndexError, "field not found");
+ return boost::python::object();
}
-static PyObject *
-RelatedRecord_sum(PyObject* self, PyObject *args, PyObject *kwargs)
+boost::python::object PyGlomRelatedRecord::generic_aggregate(const std::string& field_name, const std::string& aggregate) const
{
- PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
- return RelatedRecord_generic_aggregate(self_derived, args, kwargs, "sum");
+ const Glib::ustring related_table = (*m_relationship)->get_to_table();
+
+ //Check whether the field exists in the table.
+ //TODO_Performance: Do this without the useless Field information?
+ sharedptr<Field> field = m_document->get_field((*(m_relationship))->get_to_table(), field_name);
+ if(!field)
+ {
+ g_warning("RelatedRecord_sum: field %s not found in table %s", field_name.c_str(), (*(m_relationship))->get_to_table().c_str());
+ return boost::python::object();
+ }
+
+ //Try to get the value from the database:
+ //const Glib::ustring parent_key_name;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ sharedptr<SharedConnection> sharedconnection = ConnectionPool::get_instance()->connect();
+#else
+ std::auto_ptr<ExceptionConnection> conn_error;
+ sharedptr<SharedConnection> sharedconnection = ConnectionPool::get_instance()->connect(conn_error);
+ // Ignore error, sharedconnection presence is checked below
+#endif
+ if(!sharedconnection)
+ {
+ g_warning("RelatedRecord_sum: no connection.");
+ return boost::python::object();
+ }
+
+ Glib::RefPtr<Gnome::Gda::Connection> gda_connection = sharedconnection->get_gda_connection();
+
+ const Glib::ustring related_key_name = (*m_relationship)->get_to_field();
+
+ //Do not try to get a value based on a null key value:
+ if(!(m_from_key_value_sqlized))
+ {
+ return boost::python::object();
+ }
+
+ //Get the aggregate value from the related records:
+ const Glib::ustring sql_query = "SELECT " + aggregate + "(\"" + related_table + "\".\"" + field_name + "\") FROM \"" + related_table + "\""
+ + " WHERE \"" + related_table + "\".\"" + related_key_name + "\" = " + *m_from_key_value_sqlized;
+
+ //std::cout << "PyGlomRelatedRecord: Executing: " << sql_query << std::endl;
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query);
+#else
+ std::auto_ptr<Glib::Error> error;
+ Glib::RefPtr<Gnome::Gda::DataModel> datamodel = gda_connection->statement_execute_select(sql_query, Gnome::Gda::STATEMENT_MODEL_RANDOM_ACCESS, error);
+
+ // Ignore the error: The case that the command execution didn't return
+ // a datamodel is handled below.
+#endif
+ if(datamodel && datamodel->get_n_rows())
+ {
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+ Gnome::Gda::Value value = datamodel->get_value_at(0, 0);
+#else
+ Gnome::Gda::Value value = datamodel->get_value_at(0, 0, error);
+#endif
+ //g_warning("RelatedRecord_generic_aggregate(): value from datamodel = %s", value.to_string().c_str());
+
+ //Cache it, in case it's asked-for again.
+ (*m_pMap_field_values)[field_name] = value;
+ PyObject* cResult = glom_pygda_value_as_pyobject(value.gobj(), true /* copy */);
+ return boost::python::object(); //TODO_Hack: boost::python::object(cResult);
+ }
+ else if(!datamodel)
+ {
+ g_warning("RelatedRecord_generic_aggregate(): The datamodel was null.");
+ ConnectionPool::handle_error_cerr_only();
+ RelatedRecord_HandlePythonError();
+ }
+ else
+ {
+ g_warning("RelatedRecord_generic_aggregate(): No related records exist yet for relationship %s.", (*m_relationship)->get_name().c_str());
+ }
+
+ return boost::python::object();
}
-static PyObject *
-RelatedRecord_count(PyObject* self, PyObject *args, PyObject *kwargs)
+boost::python::object PyGlomRelatedRecord::sum(const std::string& field_name) const
{
- PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
- return RelatedRecord_generic_aggregate(self_derived, args, kwargs, "count");
+ return generic_aggregate(field_name, "sum");
}
-static PyObject *
-RelatedRecord_min(PyObject* self, PyObject *args, PyObject *kwargs)
+boost::python::object PyGlomRelatedRecord::count(const std::string& field_name) const
{
- PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
- return RelatedRecord_generic_aggregate(self_derived, args, kwargs, "min");
+ return generic_aggregate(field_name, "count");
}
-static PyObject *
-RelatedRecord_max(PyObject* self, PyObject *args, PyObject *kwargs)
+boost::python::object PyGlomRelatedRecord::min(const std::string& field_name) const
{
- PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
- return RelatedRecord_generic_aggregate(self_derived, args, kwargs, "max");
+ return generic_aggregate(field_name, "min");
}
-static PyMethodDef RelatedRecord_methods[] = {
- {(char*)"sum", (PyCFunction)RelatedRecord_sum, METH_VARARGS | METH_KEYWORDS,
- (char*)"Add all values of the field in the related records."
- },
- {(char*)"count", (PyCFunction)RelatedRecord_count, METH_VARARGS | METH_KEYWORDS,
- (char*)"Count all values in the field in the related records."
- },
- {(char*)"min", (PyCFunction)RelatedRecord_min, METH_VARARGS | METH_KEYWORDS,
- (char*)"Minimum of all values of the field in the related records."
- },
- {(char*)"max", (PyCFunction)RelatedRecord_max, METH_VARARGS | METH_KEYWORDS,
- (char*)"Maximum of all values of the field in the related records."
- },
- {0, 0, 0, 0} /* Sentinel */
-};
-
-
-
-
-static PyTypeObject pyglom_RelatedRecordType = {
- PyObject_HEAD_INIT(0)
- 0, /*ob_size*/
- (char*)"glom.RelatedRecord", /*tp_name*/
- sizeof(PyGlomRelatedRecord), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)RelatedRecord_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- &RelatedRecord_tp_as_mapping, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- (char*)"Glom objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- RelatedRecord_methods, /* tp_methods */
- 0 /* RelatedRecord_members */, /* tp_members */
- 0, /* RelatedRecord_getseters, */ /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)RelatedRecord_init, /* tp_init */
- 0, /* tp_alloc */
- RelatedRecord_new, /* tp_new */
- 0, 0, 0, 0, 0, 0, 0, 0, //TODO: or one more 0 if using a newer Python.
-};
-
-PyTypeObject* PyGlomRelatedRecord_GetPyType()
+boost::python::object PyGlomRelatedRecord::max(const std::string& field_name) const
{
- return &pyglom_RelatedRecordType;
+ return generic_aggregate(field_name, "max");
}
-
void PyGlomRelatedRecord_SetRelationship(PyGlomRelatedRecord* self, const sharedptr<const Relationship>& relationship, const Glib::ustring& from_key_value_sqlized, Document* document)
{
self->m_relationship = new sharedptr<const Relationship>(relationship);
diff --git a/glom/libglom/python_embed/py_glom_relatedrecord.h b/glom/libglom/python_embed/py_glom_relatedrecord.h
index 8b2db84..651fa95 100644
--- a/glom/libglom/python_embed/py_glom_relatedrecord.h
+++ b/glom/libglom/python_embed/py_glom_relatedrecord.h
@@ -22,6 +22,7 @@
#define GLOM_PYTHON_GLOM_RELATEDRECORD_H
#define NO_IMPORT_PYGTK //To avoid a multiple definition in pygtk.
+#include <boost/python.hpp>
#include <pygtk/pygtk.h> //For the PyGObject and PyGBoxed struct definitions.
#include <libglom/document/document.h>
@@ -33,10 +34,24 @@ namespace Glom
class PyGlomRecord;
-struct PyGlomRelatedRecord
+class PyGlomRelatedRecord
{
public:
- PyObject_HEAD
+ PyGlomRelatedRecord();
+ ~PyGlomRelatedRecord();
+
+ boost::python::object sum(const std::string& field_name) const;
+ boost::python::object count(const std::string& field_name) const;
+ boost::python::object min(const std::string& field_name) const;
+ boost::python::object max(const std::string& field_name) const;
+
+ //[] notation:
+ long len() const;
+ boost::python::object getitem(boost::python::object item);
+
+//TODO: protected:
+
+ boost::python::object generic_aggregate(const std::string& field_name, const std::string& aggregate) const;
//PyObject* m_fields_dict; //Dictionary (map) of field names (string) to field values (Gnome::Gda::Value).
PyGObject* m_py_gda_connection; //"derived" from PyObject.
diff --git a/glom/main.cc b/glom/main.cc
index 52c2190..29bbd45 100644
--- a/glom/main.cc
+++ b/glom/main.cc
@@ -21,7 +21,8 @@
#include <config.h>
//We use Python for calculated fields.
-#include <Python.h> //Include it before anything else to avoid "_POSIX_C_SOURCE redefined".
+//#include <Python.h> //Include it before anything else to avoid "_POSIX_C_SOURCE redefined".
+#include <boost/python.hpp>
//#include <gnome.h>
#include <glom/libglom/init.h>
diff --git a/glom/python_embed/glom_python.cc b/glom/python_embed/glom_python.cc
index 3ac76d7..444e2b3 100644
--- a/glom/python_embed/glom_python.cc
+++ b/glom/python_embed/glom_python.cc
@@ -23,12 +23,10 @@
#include <libglom/python_embed/py_glom_record.h>
#include <libglom/python_embed/pygdavalue_conversions.h>
-#define NO_IMPORT_PYGTK //To avoid a multiple definition in pygtk.
-#include <pygtk/pygtk.h> //For the PyGObject and PyGBoxed struct definitions.
-
-#include <Python.h>
-#include <compile.h> /* for the PyCodeObject */
-#include <eval.h> /* for PyEval_EvalCode */
+//#include <Python.h>
+//#include <compile.h> /* for the PyCodeObject */
+//#include <eval.h> /* for PyEval_EvalCode */
+#include <boost/python.hpp>
#include "glom_python.h"
#include <libglom/data_structure/glomconversions.h>
@@ -41,7 +39,7 @@
namespace Glom
{
-std::list<Glib::ustring> ustring_tokenize(const Glib::ustring& msg, const Glib::ustring& separators, int maxParts)
+static std::list<Glib::ustring> ustring_tokenize(const Glib::ustring& msg, const Glib::ustring& separators, int maxParts)
{
std::list<Glib::ustring> result;
Glib::ustring str = msg;
@@ -102,18 +100,17 @@ void ShowTrace()
if(!tbList)
{
- std::cerr << "format_exception failed" << std::endl;
+ std::cerr << "Glom: format_exception failed" << std::endl;
return;
}
- PyObject* emptyString = PyString_FromString("");
- PyObject* strRetval = PyObject_CallMethod(emptyString, (char*)"join",
+ boost::python::str emptyString("");
+ PyObject* strRetval = PyObject_CallMethod(emptyString.ptr(), (char*)"join",
(char*)"O", tbList);
if(strRetval)
chrRetval = g_strdup(PyString_AsString(strRetval));
Py_DECREF(tbList);
- Py_DECREF(emptyString);
Py_DECREF(strRetval);
Py_DECREF(tracebackModule);
}
@@ -201,9 +198,8 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
func_def = "def " + func_name + "(record):\n import glom_" GLOM_ABI_VERSION_UNDERLINED "\n import gda\n" + func_def;
//We did this in main(): Py_Initialize();
- PyObject* pMain = PyImport_AddModule((char*)"__main__");
- PyObject* pDict = PyModule_GetDict(pMain);
-
+ boost::python::object pMain = boost::python::import("__main__");
+ boost::python::dict pDict = boost::python::extract<boost::python::dict>( pMain.attr("__dict__") ); //TODO: Does boost::python have an equivalent for PyModule_GetDict()?
//Allow the function to import from our script library:
if(pDocument)
@@ -215,6 +211,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
const Glib::ustring script = pDocument->get_library_module(name);
if(!name.empty() && !script.empty())
{
+ //TODO: Is there a boost::python equivalent for Py_CompileString()?
PyObject* objectCompiled = Py_CompileString(script.c_str(), name.c_str() /* "filename", for debugging info */, Py_file_input /* "start token" for multiple lines of code. */); //Returns a reference.
if(!objectCompiled)
@@ -267,7 +264,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//Create the function definition:
- PyObject* pyValue = PyRun_String(func_def.c_str(), Py_file_input, pDict, pDict);
+ PyObject* pyValue = PyRun_String(func_def.c_str(), Py_file_input, pDict.ptr(), pDict.ptr());
if(pyValue)
{
Py_DECREF(pyValue);
@@ -280,7 +277,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//Call the function:
{
- PyObject* pFunc = PyDict_GetItemString(pDict, func_name.c_str()); //The result is borrowed, so should not be dereferenced.
+ PyObject* pFunc = PyDict_GetItemString(pDict.ptr(), func_name.c_str()); //The result is borrowed, so should not be dereferenced.
if(!pFunc)
{
HandlePythonError();
@@ -301,9 +298,11 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
PyGlomRecord* pParam = (PyGlomRecord*)PyObject_Call((PyObject*)pyTypeGlomRecord, new_args, 0);
//PyGlomRecord* pParam = (PyGlomRecord*)PyObject_Call((PyObject*)PyGlomRecord_GetPyType(), new_args, 0);
Py_DECREF(new_args);
+ new_args = 0;
+
if(pParam)
{
- Py_INCREF(pParam); //TODO: As I understand it, PyObject_New() should return a new reference, so this should not be necessary.
+ Py_INCREF((PyObject*)pParam); //TODO: As I understand it, PyObject_New() should return a new reference, so this should not be necessary.
//Fill the record's details:
PyGlomRecord_SetFields(pParam, field_values, pDocument, table_name, opened_connection);
@@ -348,7 +347,6 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//instead of returning 0.
if(pyResult == Py_None) //Direct comparison is possible and recommended, because there is only one pyNone object.
{
-
//The result should be an appropriate empty value for this field type:
valueResult = Conversions::get_empty_value(result_type);
//std::cout << "DEBUG: glom_evaluate_python_function_implementation(): empty value Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
@@ -359,26 +357,28 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//(though I don't think this code is ever reached. murrayc)
//Treat this as a string or something that can be converted to a string:
- PyObject* pyObjectResult = PyObject_Str(pyResult);
- if(PyString_Check(pyObjectResult))
+ const char* pchResult = 0;
+ try
+ {
+ pchResult = boost::python::extract<const char*>(pyResult);
+ }
+ catch(const boost::python::error_already_set& ex)
{
- const char* pchResult = PyString_AsString(pyObjectResult);
- if(pchResult)
- {
- bool success = false;
- valueResult = Conversions::parse_value(result_type, pchResult, success, true /* iso_format */);
- std::cout << "DEBUG: glom_evaluate_python_function_implementation(): parsed value Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
-
- }
- else
- HandlePythonError();
+ std::cerr << "Glom: Exception caught from boost::python::extract() while converting result to a const char*." << std::endl << func_name << std::endl;
+ ShowTrace();
+ return valueResult;
+ }
+
+ if(pchResult)
+ {
+ bool success = false;
+ valueResult = Conversions::parse_value(result_type, pchResult, success, true /* iso_format */);
+ std::cout << "DEBUG: glom_evaluate_python_function_implementation(): parsed value Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
}
else
HandlePythonError();
}
}
-
- Py_DECREF(pyResult);
}
}
}
diff --git a/glom/python_embed/python_module/py_glom_module.cc b/glom/python_embed/python_module/py_glom_module.cc
index 790bafa..4ad0472 100644
--- a/glom/python_embed/python_module/py_glom_module.cc
+++ b/glom/python_embed/python_module/py_glom_module.cc
@@ -20,7 +20,7 @@
#include <config.h>
//We need to include this before anything else, to avoid redefinitions:
-#include <Python.h>
+#include <boost/python.hpp>
#include <compile.h> /* for the PyCodeObject */
#include <eval.h> /* for PyEval_EvalCode */
#include <objimpl.h> /* for PyObject_New() */
@@ -29,46 +29,36 @@
#include <libglom/python_embed/py_glom_related.h>
#include <libglom/python_embed/py_glom_relatedrecord.h>
-static PyMethodDef pyglom_methods[] = {
- {0, 0, 0, 0} /* Sentinel */
-};
+using namespace Glom;
-PyMODINIT_FUNC
-initglom_1_14(void)
+BOOST_PYTHON_MODULE(glom)
{
- PyObject* m;
-
- //pyglom_RecordType.tp_new = PyType_GenericNew;
-
- if(PyType_Ready(Glom::PyGlomRecord_GetPyType()) < 0)
- return;
-
- if(PyType_Ready(Glom::PyGlomRelated_GetPyType()) < 0)
- return;
-
- if(PyType_Ready(Glom::PyGlomRelatedRecord_GetPyType()) < 0)
- return;
-
-
- m = Py_InitModule3((char*)"glom_" GLOM_ABI_VERSION_UNDERLINED, pyglom_methods,
- (char*)"Python module for Glom caluclated fields.");
-
-
- Py_INCREF(Glom::PyGlomRecord_GetPyType());
- PyModule_AddObject(m, (char*)"Record", (PyObject *)Glom::PyGlomRecord_GetPyType());
-
- Py_INCREF(Glom::PyGlomRelated_GetPyType());
- PyModule_AddObject(m, (char*)"Related", (PyObject *)Glom::PyGlomRelated_GetPyType());
-
- Py_INCREF(Glom::PyGlomRelated_GetPyType());
- PyModule_AddObject(m, (char*)"RelatedRecord", (PyObject *)Glom::PyGlomRelated_GetPyType());
-
-
- if(PyErr_Occurred())
- Py_FatalError((char*)"Can't initialise glom module");
+ boost::python::class_<PyGlomRecord>("Record")
+ .add_property("table_name", &PyGlomRecord::get_table_name)
+ .add_property("connection", &PyGlomRecord::get_connection)
+ .add_property("related", &PyGlomRecord::get_related)
+
+ /* TODO: python still says "TypeError: 'Boost.Python.class' object is unsubscriptable" */
+ /* This suggests that it should work: http://lists.boost.org/boost-users/2003/08/4750.php */
+ .def("__getitem__", &PyGlomRecord::getitem)
+ .def("__len__", &PyGlomRecord::len)
+ ;
+
+ boost::python::class_<PyGlomRelated>("Related")
+ .def("__getitem__", &PyGlomRelated::getitem)
+ .def("__len__", &PyGlomRelated::len)
+ ;
+
+ boost::python::class_<PyGlomRelatedRecord>("RelatedRecord")
+ .def("sum", &PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Add all values of the field in the related records.")
+ .def("count", &PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Count all values in the field in the related records.")
+ .def("min", &PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Minimum of all values of the field in the related recordss.")
+ .def("max", &PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Maximum of all values of the field in the related records.")
+ .def("__getitem__", &PyGlomRecord::getitem)
+ .def("__len__", &PyGlomRecord::len)
+ ;
}
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]