# HG changeset patch # User David Grundberg # Date 1226912572 -3600 # Node ID 905659caf44beff5e99112ce73f261c07b4bb958 # Parent ae09a25b1206d29c2df7d35377280c7d440b13b2# Parent 9a773d71a973d2dc41a24df516c4f2f30269fb62 Support for Python lists and dictionaries (cell arrays and structs) diff -r ae09a25b1206 -r 905659caf44b octave_to_python.cc --- a/octave_to_python.cc Mon Nov 10 22:00:20 2008 +0100 +++ b/octave_to_python.cc Mon Nov 17 10:02:52 2008 +0100 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "pytavedefs.h" @@ -42,6 +43,9 @@ namespace pytave { + void octvalue_to_pyobj(boost::python::object &py_object, + const octave_value& octvalue); + template static void copy_octarray_to_pyarrobj( PyArrayObject *pyarr, @@ -250,6 +254,40 @@ py_object = object(handle((PyObject *)pyarr)); } + + static void octcell_to_pyobject(boost::python::object &py_object, + const Cell& cell) { + py_object = boost::python::list(); + + if(cell.dim1() != 1) { + throw value_convert_exception( + "Only one dimensional cell arrays are allowed, " + "conversion not implemented"); + } + + for(octave_idx_type i = 0 ; i < cell.length(); i++) { + boost::python::object py_val; + + octvalue_to_pyobj(py_val, cell.elem(i)); + + ((boost::python::list&)py_object).insert(i, py_val); + } + } + + static void octmap_to_pyobject(boost::python::object &py_object, + const Octave_map& map) { + py_object = boost::python::dict(); + string_vector keys = map.keys(); + + for(octave_idx_type i = 0 ; i < keys.length(); i++) { + boost::python::object py_val; + + octvalue_to_pyobj(py_val, map.contents(keys[i])); + + py_object[keys[i]] = py_val; + } + } + void octvalue_to_pyobj(boost::python::object &py_object, const octave_value& octvalue) { if (octvalue.is_scalar_type()) { @@ -266,6 +304,10 @@ py_object = str(octvalue.string_value()); else if (octvalue.is_matrix_type()) octvalue_to_pyarr(py_object, octvalue); + else if (octvalue.is_map()) + octmap_to_pyobject(py_object, octvalue.map_value()); + else if (octvalue.is_cell()) + octcell_to_pyobject(py_object, octvalue.cell_value()); else if (octvalue.is_undefined()) throw value_convert_exception( "Octave value `undefined'. Can not convert to a Python object"); @@ -285,8 +327,9 @@ } python_tuple = tuple(seq); } + + } - /* Emacs * Local Variables: * fill-column:79 diff -r ae09a25b1206 -r 905659caf44b python_to_octave.cc --- a/python_to_octave.cc Mon Nov 10 22:00:20 2008 +0100 +++ b/python_to_octave.cc Mon Nov 17 10:02:52 2008 +0100 @@ -23,6 +23,8 @@ #include "arrayobjectdefs.h" #undef HAVE_STAT /* both boost.python and octave defines HAVE_STAT... */ #include +#include +#include #include #include @@ -34,6 +36,10 @@ namespace pytave { + + void pyobj_to_octvalue(octave_value &oct_value, + const boost::python::object &py_object); + template static void copy_pyarrobj_to_octarray(OctaveBase &matrix, const PyArrayObject* const pyarr, @@ -107,7 +113,7 @@ } static void pyarr_to_octvalue(octave_value &octvalue, - const PyArrayObject *pyarr) { + const PyArrayObject *pyarr) { if (pyarr->nd < 1) throw object_convert_exception("Less than 1 dimensions not supported"); @@ -182,12 +188,107 @@ } } + static void pylist_to_cellarray(octave_value &oct_value, + const boost::python::list &list) { + + size_t length = boost::python::extract(list.attr("__len__")()); + octave_value_list values; + + for(octave_idx_type i = 0; i < length; i++) { + octave_value val; + + pyobj_to_octvalue(val, list[i]); + values.append(val); + + } + + oct_value = Cell(values); + } + + + + static void pydict_to_octmap(octave_value &oct_value, + const boost::python::dict &dict) { + + boost::python::list list = dict.items(); + size_t length = boost::python::extract(list.attr("__len__")()); + + dim_vector dims = dim_vector(1, 1); + + bool has_dimensions = false; + + + for(octave_idx_type i = 0; i < length; i++) { + octave_value val; + + boost::python::tuple tuple = + boost::python::extract(list[i])(); + + pyobj_to_octvalue(val, tuple[1]); + + if(val.is_cell()) { + const Cell c(val.cell_value()); + + if(c.dims().length() == 2 && + (c.dims()(0) >= 1 && c.dims()(1) > 1) || + (c.dims()(0) > 1 && c.dims()(1) >= 1)) { + + if(!has_dimensions) { + + dims = c.dims(); + has_dimensions = true; + } else if(c.dims() != dims) { + throw object_convert_exception( + "Dimensions of the parameters to struct do not match"); + } + } + } + } + + + Octave_map map = Octave_map(dims); + + for(octave_idx_type i = 0; i < length; i++) { + octave_value val; + std::string key; + + boost::python::tuple tuple = + boost::python::extract(list[i])(); + + boost::python::extract str(tuple[0]); + if(!str.check()) { + throw object_convert_exception( + "Keys in the python dictionaries must be strings"); + } + + key = str(); + + pyobj_to_octvalue(val, tuple[1]); + + if(!val.is_cell()) + map.assign(key, Cell(dims, val)); + else { + const Cell c(val.cell_value()); + + if(c.dims().length() == 2 && c.dims()(0) == 1 && c.dims()(1) == 1) + map.assign(key, Cell(dims, c(0))); + else + map.assign(key, c); + } + } + + oct_value = map; + } + + void pyobj_to_octvalue(octave_value &oct_value, - const boost::python::object &py_object) { + const boost::python::object &py_object) { extract intx(py_object); extract doublex(py_object); extract stringx(py_object); extract arrayx(py_object); + extract listx(py_object); + extract dictx(py_object); if (intx.check()) { oct_value = intx(); } else if (doublex.check()) { @@ -196,6 +297,10 @@ pyarr_to_octvalue(oct_value, (PyArrayObject*)py_object.ptr()); } else if (stringx.check()) { oct_value = stringx(); + } else if (listx.check()) { + pylist_to_cellarray(oct_value, (boost::python::list&)py_object); + } else if (dictx.check()) { + pydict_to_octmap(oct_value, (boost::python::dict&)py_object); } else { throw object_convert_exception( PyEval_GetFuncName(py_object.ptr()) @@ -206,7 +311,7 @@ } void pytuple_to_octlist(octave_value_list &octave_list, - const boost::python::tuple &python_tuple) { + const boost::python::tuple &python_tuple) { int length = extract(python_tuple.attr("__len__")()); for (int i = 0; i < length; i++) {