[glom/boostpython] Starting to use boost::python



commit 63764f48ebf93705c25bcfe843ae5cf00db478f1
Author: Murray Cumming <murrayc murrayc com>
Date:   Sun May 10 00:37:39 2009 +0200

    Starting to use boost::python
---
 configure.ac                                       |    7 +
 glom/Makefile.am                                   |    5 +-
 glom/libglom/connectionpool.cc                     |    2 +-
 glom/libglom/python_embed/py_glom_record.cc        |  179 +++-------------
 glom/libglom/python_embed/py_glom_record.h         |   20 ++-
 glom/libglom/python_embed/py_glom_related.cc       |  145 ++-----------
 glom/libglom/python_embed/py_glom_related.h        |   17 ++-
 glom/libglom/python_embed/py_glom_relatedrecord.cc |  223 ++++----------------
 glom/libglom/python_embed/py_glom_relatedrecord.h  |   19 ++-
 glom/main.cc                                       |    3 +-
 glom/python_embed/glom_python.cc                   |   75 ++++---
 glom/python_embed/python_module/Makefile.am        |    2 +-
 glom/python_embed/python_module/py_glom_module.cc  |   68 +++----
 13 files changed, 215 insertions(+), 550 deletions(-)

diff --git a/configure.ac b/configure.ac
index bb1c519..b89a76f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -163,6 +163,13 @@ AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes
 # Get the CFLAGS and LIBS for python's embedding API:
 AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
 
+BOOST_PYTHON_LIBS="-lboost_python-gcc43-mt-1_39"
+AC_SUBST([BOOST_PYTHON_LIBS])
+
+#These don't work. pyconfig.h can't be found when using python.hpp.
+#AX_PYTHON()
+#AX_BOOST_PYTHON()
+
 # We don't have this on mingw, for example
 AC_CHECK_FUNCS(strptime)
 
diff --git a/glom/Makefile.am b/glom/Makefile.am
index 763e60b..58e8b71 100644
--- a/glom/Makefile.am
+++ b/glom/Makefile.am
@@ -92,7 +92,7 @@ glom_LDADD += bakery/libbakery_app.a \
 
 glom_LDADD += python_embed/libpython_embed.a \
               $(top_builddir)/glom/libglom/libglom-1.0.la \
-              $(GLOM_LIBS) $(PYTHON_LDFLAGS) $(MAEMO_LAUNCHER_LIBS)
+              $(GLOM_LIBS) $(BOOST_PYTHON_LIBS) $(PYTHON_LDFLAGS) $(MAEMO_LAUNCHER_LIBS)
 
 if !WIN32
 glom_LDADD += -lutil
@@ -114,6 +114,9 @@ glom_LDADD += -lgettextpo
 test_pyembed_SOURCES = test_pyembed.cc
 test_pyembed_LDADD = $(GLOM_LIBS) $(PYTHON_LDFLAGS)
 
+test_pyembed_boost_SOURCES = test_pyembed_boost.cc
+test_pyembed_boost_LDADD = $(GLOM_LIBS) $(BOOST_PYTHON_LIBS) $(PYTHON_LDFLAGS)
+
 if !WIN32
 test_pyembed_LDADD += -lutil
 endif
diff --git a/glom/libglom/connectionpool.cc b/glom/libglom/connectionpool.cc
index 480805d..3d31895 100644
--- a/glom/libglom/connectionpool.cc
+++ b/glom/libglom/connectionpool.cc
@@ -630,7 +630,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 7ec8ef9..237ebde 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", NULL};
 
@@ -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,36 @@ 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));
@@ -157,48 +116,24 @@ Record__get_related(PyObject* self, void* /* closure */)
     PyGlomRelated_SetRelationships(self_record->m_related, map_relationships);
 
     self_record->m_related->m_record = self_record;
-    Py_XINCREF(self_record); //unreffed in the self->m_related's _dealloc. //TODO: Is this a circular reference?
   }
 
-  Py_INCREF(self_record->m_related); //Should we do this?
-  return (PyObject*)self_record->m_related;
+  PyObject* cobject = (PyObject*)self_record->m_related;
+  //TODO: Py_INCREF(cobject); //Should we do this?
+  return boost::python::object( boost::python::borrowed(cobject) );
 }
 
-
-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
-    },
-    {NULL, 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)
+long PyGlomRecord::length() const
 {
-  PyGlomRecord *self_record = (PyGlomRecord*)self;
+  const PyGlomRecord *self_record = this;
   return self_record->m_pMap_field_values->size();
 }
-#else
-static int
-Record_tp_as_mapping_length(PyObject *self)
-{
-  PyGlomRecord *self_record = (PyGlomRecord*)self;
-  return (int)(self_record->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;
+  PyGlomRecord *self_record = this;
+
+  PyObject* item = cppitem.ptr();
 
   if(PyString_Check(item))
   {
@@ -211,11 +146,13 @@ Record_tp_as_mapping_getitem(PyObject *self, PyObject *item)
         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 pygda_value_as_pyobject(iterFind->second.gobj(), true /* copy */);
+          PyObject* cobject = pygda_value_as_pyobject(iterFind->second.gobj(), true /* copy */);
+          //Py_INCREF((PyObject*)cobject);
+          return boost::python::object(boost::python::borrowed(cobject));
         }
         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);
+          g_warning("Record_tp_as__getitem(): item not found in m_pMap_field_values. size=%d, item=%s", (int)self_record->m_pMap_field_values->size(), pchKey);
         }
       }
       else
@@ -236,7 +173,7 @@ Record_tp_as_mapping_getitem(PyObject *self, PyObject *item)
 
   g_warning("Record_tp_as_mapping_getitem(): return null.");
   PyErr_SetString(PyExc_IndexError, "field not found");
-  return NULL;
+  return boost::python::object(); //TODO: NULL;
 }
 
 /*
@@ -248,62 +185,6 @@ Record_tp_as_mapping_setitem(PyGObject *self, PyObject *item, PyObject *value)
 }
 */
 
-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(NULL)
-    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,
-};
-
-PyTypeObject* PyGlomRecord_GetPyType()
-{
-  return &pyglom_RecordType;
-}
-
-
 
 /*
 static void Record_HandlePythonError()
diff --git a/glom/libglom/python_embed/py_glom_record.h b/glom/libglom/python_embed/py_glom_record.h
index 8bf072b..201be79 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 length() 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;
diff --git a/glom/libglom/python_embed/py_glom_related.cc b/glom/libglom/python_embed/py_glom_related.cc
index 65b9611..77ade1a 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::~PyGlomRelated()
 {
-  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 *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::length() 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,82 +156,9 @@ Related_tp_as_mapping_getitem(PyObject *self, PyObject *item)
   }
 
   PyErr_SetString(PyExc_IndexError, "relationship not found");
-  return NULL;
-}
-
-/*
-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(NULL)
-    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,
-};
-
-PyTypeObject* PyGlomRelated_GetPyType()
-{
-  return &pyglom_RelatedType;
+  return boost::python::object(); //Is this the same as returning a NULL PyObject*, meaning an error occurred?
 }
 
-/*
-static void Related_HandlePythonError()
-{
-  if(PyErr_Occurred())
-    PyErr_Print();
-}
-*/
-
-
 void PyGlomRelated_SetRelationships(PyGlomRelated* self, const PyGlomRelated::type_map_relationships& relationships)
 {
   *(self->m_pMap_relationships) = relationships;
diff --git a/glom/libglom/python_embed/py_glom_related.h b/glom/libglom/python_embed/py_glom_related.h
index 1bbaf9f..2484318 100644
--- a/glom/libglom/python_embed/py_glom_related.h
+++ b/glom/libglom/python_embed/py_glom_related.h
@@ -28,18 +28,29 @@ namespace Glom
 {
 
 class PyGlomRelatedRecord;
+class PyGlomRecord;
 
 class PyGlomRelated
 {
 public:
-  PyObject_HEAD
+  PyGlomRelated();
+  ~PyGlomRelated();
 
-  PyGlomRecord* m_record; //A reference to the parent record.
+  //[] notation:
+  long length() 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;
 };
 
diff --git a/glom/libglom/python_embed/py_glom_relatedrecord.cc b/glom/libglom/python_embed/py_glom_relatedrecord.cc
index 1008534..df2d98a 100644
--- a/glom/libglom/python_embed/py_glom_relatedrecord.cc
+++ b/glom/libglom/python_embed/py_glom_relatedrecord.cc
@@ -37,12 +37,9 @@
 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()
 {
-  PyGlomRelatedRecord *self  = (PyGlomRelatedRecord*)type->tp_alloc(type, 0);
+  PyGlomRelatedRecord *self = this;
   if(self)
   {
     self->m_py_gda_connection = 0;
@@ -54,39 +51,12 @@ RelatedRecord_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds
 
     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 */)
+PyGlomRelatedRecord::~PyGlomRelatedRecord()
 {
-  //static char *kwlist[] = {"test", NULL};
-
-  //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();
-  }
+  PyGlomRelatedRecord *self = this;
 
-  return 0;
-}
-
-static void
-RelatedRecord_dealloc(PyGlomRelatedRecord* self)
-{
   if(self->m_pMap_field_values)
   {
     delete self->m_pMap_field_values;
@@ -110,8 +80,6 @@ RelatedRecord_dealloc(PyGlomRelatedRecord* self)
     Py_XDECREF( (PyObject*)(self->m_py_gda_connection));
     self->m_py_gda_connection = 0;
   }
-
-  self->ob_type->tp_free((PyObject*)self);
 }
 
 /*
@@ -131,31 +99,6 @@ RelatedRecord__get_fields(PyGlomRelatedRecord *self, void * closure )
 }
 */
 
-/*
-static PyGetSetDef RelatedRecord_getseters[] = {
-    {"fields",
-     (getter)RelatedRecord__get_fields, (setter)0, 0, 0
-    },
-    {NULL, 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,10 +106,15 @@ static void RelatedRecord_HandlePythonError()
     PyErr_Print();
 }
 
-static PyObject *
-RelatedRecord_tp_as_mapping_getitem(PyObject *self, PyObject *item)
+long PyGlomRelatedRecord::length() const
 {
-  PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
+  const PyGlomRelatedRecord* self_derived = this;
+  return self_derived->m_pMap_field_values->size();
+}
+
+PyObject* PyGlomRelatedRecord::getitem(PyObject *item)
+{
+  PyGlomRelatedRecord* self_derived = this;
 
   if(PyString_Check(item))
   {
@@ -266,38 +214,11 @@ RelatedRecord_tp_as_mapping_getitem(PyObject *self, PyObject *item)
   return NULL;
 }
 
-/*
-static int
-RelatedRecord_tp_as_mapping_setitem(PyGObject *self, PyObject *item, PyObject *value)
-{
-  Py_INCREF(Py_None);
-  return Py_None;
-}
-*/
-
-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::generic_aggregate(const std::string& field_name, const std::string& aggregate) const
 {
-  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 NULL;
-
-  if(!(PyString_Check(py_field_name)))
-    return NULL;
+  const PyGlomRelatedRecord* self = this;
 
-  const char* pchKey = PyString_AsString(py_field_name);
-  if(pchKey)
   {
-    const Glib::ustring field_name(pchKey);
     const Glib::ustring related_table = (*(self->m_relationship))->get_to_table();
 
     //Check whether the field exists in the table.
@@ -324,7 +245,11 @@ RelatedRecord_generic_aggregate(PyGlomRelatedRecord* self, PyObject *args, PyObj
 
         //Do not try to get a value based on a null key value:
         if(!(self->m_from_key_value_sqlized))
-          return Py_None;
+        {
+          PyObject* cobject = Py_None;
+          Py_INCREF(cobject); //TODO: Use boost::python for this somehow.
+          return boost::python::object( boost::python::borrowed(cobject) );
+        }
        
         //Get the aggregate value from the related records:
         const Glib::ustring sql_query = "SELECT " + aggregate + "(\"" + related_table + "\".\"" + field_name + "\") FROM \"" + related_table + "\""
@@ -347,7 +272,9 @@ RelatedRecord_generic_aggregate(PyGlomRelatedRecord* self, PyObject *args, PyObj
 
           //Cache it, in case it's asked-for again.
           (*(self->m_pMap_field_values))[field_name] = value;
-          return pygda_value_as_pyobject(value.gobj(), true /* copy */);
+          
+          PyObject* cobject = pygda_value_as_pyobject(value.gobj(), true /* copy */);
+          return boost::python::object( boost::python::borrowed(cobject) );
         }
         else if(!datamodel)
         {
@@ -362,104 +289,30 @@ RelatedRecord_generic_aggregate(PyGlomRelatedRecord* self, PyObject *args, PyObj
       }
     }
   }
-
-  Py_INCREF(Py_None);
-  return Py_None;
-}
-
-static PyObject *
-RelatedRecord_sum(PyObject* self, PyObject *args, PyObject *kwargs)
-{
-  PyGlomRelatedRecord* self_derived = (PyGlomRelatedRecord*)self;
-  return RelatedRecord_generic_aggregate(self_derived, args, kwargs, "sum");
+   
+  PyObject* cobject = Py_None;
+  Py_INCREF(cobject); //TODO: Use boost::python for this somehow.
+  return boost::python::object( boost::python::borrowed(cobject) );
 }
-
-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."
-    },
-    {NULL, 0, 0, 0}  /* Sentinel */
-};
-
-
-
-
-static PyTypeObject pyglom_RelatedRecordType = {
-    PyObject_HEAD_INIT(NULL)
-    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,
-};
-
-PyTypeObject* PyGlomRelatedRecord_GetPyType()
+  
+boost::python::object PyGlomRelatedRecord::max(const std::string& field_name) const
 {
-  return &pyglom_RelatedRecordType;
+  return generic_aggregate(field_name, "max");
 }
 
 
diff --git a/glom/libglom/python_embed/py_glom_relatedrecord.h b/glom/libglom/python_embed/py_glom_relatedrecord.h
index 8b2db84..4cab2cc 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 length() const;
+  PyObject* getitem(PyObject *item); //TODO: use a string parameter?
+
+//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 f3e740e..1c56de0 100644
--- a/glom/main.cc
+++ b/glom/main.cc
@@ -21,7 +21,8 @@
 #include <config.h> //For VERSION.
 
 //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 a49d83b..0d5d121 100644
--- a/glom/python_embed/glom_python.cc
+++ b/glom/python_embed/glom_python.cc
@@ -22,12 +22,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>
@@ -40,7 +38,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;
@@ -64,33 +62,36 @@ std::list<Glib::ustring> ustring_tokenize(const Glib::ustring& msg, const Glib::
 }
 
 // Use this for errors not (directly) caused by the user
-void HandlePythonError()
+static void HandlePythonError()
 {
   if(PyErr_Occurred())
     PyErr_Print();
 }
 
 // Show python coding errors of the user
-void ShowTrace()
+static void ShowTrace()
 {
   // Python equivilant:
   // import traceback, sys
   // return "".join(traceback.format_exception(sys.exc_type,
   //    sys.exc_value, sys.exc_traceback))
 
-  PyObject *type, *value, *traceback;
-
+  PyObject* type = 0;
+  PyObject* value = 0;
+  PyObject* traceback = 0;
   PyErr_Fetch(&type, &value, &traceback);
   
   if(!traceback)
   {
     std::cerr << "traceback = 0" << std::endl;
+    return;
   }
 
   PyObject *tracebackModule = PyImport_ImportModule((char*)"traceback");
   gchar* chrRetval = 0;
   if(tracebackModule != NULL)
   {
+      //TODO: What is the boost::python equivalent of PyObject_CallMethod()?
       PyObject* tbList = PyObject_CallMethod(
           tracebackModule,
           (char*)"format_exception",
@@ -101,18 +102,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);
     }
@@ -186,9 +186,8 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
   func_def = "def " + func_name + "(record):\n  import glom\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)
@@ -200,6 +199,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)
@@ -252,7 +252,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);
@@ -265,7 +265,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();
@@ -286,9 +286,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);
@@ -333,7 +335,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;
@@ -344,26 +345,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/Makefile.am b/glom/python_embed/python_module/Makefile.am
index ea7d8fc..8b9e2eb 100644
--- a/glom/python_embed/python_module/Makefile.am
+++ b/glom/python_embed/python_module/Makefile.am
@@ -10,7 +10,7 @@ pyexec_LTLIBRARIES = glom.la
 glom_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initglom
 
 glom_la_LIBADD = $(top_builddir)/glom/libglom/libglom-1.0.la \
-                 $(GLOM_LIBS) $(PYTHON_LDFLAGS)
+                 $(GLOM_LIBS) $(BOOST_PYTHON_LIBS) $(PYTHON_LDFLAGS)
 
 if !WIN32
 glom_la_LIBADD += -lutil
diff --git a/glom/python_embed/python_module/py_glom_module.cc b/glom/python_embed/python_module/py_glom_module.cc
index e0f84f3..e823a4f 100644
--- a/glom/python_embed/python_module/py_glom_module.cc
+++ b/glom/python_embed/python_module/py_glom_module.cc
@@ -19,7 +19,7 @@
  */
 
 //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() */
@@ -28,46 +28,32 @@
 #include <libglom/python_embed/py_glom_related.h>
 #include <libglom/python_embed/py_glom_relatedrecord.h>
 
-static PyMethodDef pyglom_methods[] = {
-    {NULL, 0, 0, 0}  /* Sentinel */
-};
-
-PyMODINIT_FUNC
-initglom(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", 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_<Glom::PyGlomRecord>("Record")
+        .add_property("table_name", &Glom::PyGlomRecord::get_table_name)
+        .add_property("connection", &Glom::PyGlomRecord::get_connection)
+        .add_property("related", &Glom::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__", &Glom::PyGlomRecord::getitem)
+        .def("__len__", &Glom::PyGlomRecord::length)
+    ;
+
+    boost::python::class_<Glom::PyGlomRelated>("Related")
+        .def("__getitem__", &Glom::PyGlomRelated::getitem)
+        .def("__len__", &Glom::PyGlomRelated::length)
+    ;
+
+    boost::python::class_<Glom::PyGlomRelatedRecord>("RelatedRecord")
+        .def("sum", &Glom::PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Add all values of the field in the related records.")
+        .def("count", &Glom::PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Count all values in the field in the related records.")
+        .def("min", &Glom::PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Minimum of all values of the field in the related recordss.")
+        .def("max", &Glom::PyGlomRelatedRecord::sum, boost::python::args("field_name"), "Maximum of all values of the field in the related records.")
+
+        .def("__getitem__", &Glom::PyGlomRecord::getitem)
+        .def("__len__", &Glom::PyGlomRecord::length)
+    ;
 }
 
-
-
-
-



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]