# HG changeset patch # User Mike Miller # Date 1470957155 25200 # Node ID c2aa34730dc9dbaa7e3e077607dcb062b0f80f99 # Parent 1231dc878600eb32ddf4f3e895488091892c05a9 Convert scalar struct into Python dict (fixes issue #57) * oct-py-types.cc, oct-py-types.h: New files for conversion of objects between Octave and Python APIs. * Makefile.am (COMMON_SOURCE_FILES, PYTAVE_HEADER_FILES): Include new files. * octave_to_python.cc (pytave::octvalue_to_pyobj): Add case to handle scalar struct instead of struct array. * @pyobject/pyobject.m: Add %!tests for pyobject from scalar struct and %!error tests for failure with struct array. diff -r 1231dc878600 -r c2aa34730dc9 @pyobject/pyobject.m --- a/@pyobject/pyobject.m Wed Aug 10 10:21:22 2016 -0700 +++ b/@pyobject/pyobject.m Thu Aug 11 16:12:35 2016 -0700 @@ -275,6 +275,21 @@ %!assert (ndims (a), 3) %!shared +## Test conversion of scalar struct into a Python dict +%!shared s1 +%! s1.name = "Octave"; +%! s1.value = 42; +%! s1.counts = {1, 2, 3}; +%! s1.ok = true; +%!assert (isa (pyobject (s1), "pyobject")) +%!assert (class (pyobject (s1)), "py.dict") +%!assert (char (pyobject (s1){"name"}), "Octave") +%!assert (pyobject (s1){"value"}, 42) +%!assert (pyobject (s1){"ok"}, true) + +%!error pyobject (struct ("a", {})) +%!error pyobject (struct ("a", {1, 2})) + %!assert (char (pyeval ("None")), "None") %!assert (char (pyeval ("'this is a string'")), "this is a string") %!assert (char (pyeval ("[1, 2, 3, 4, 5]")), "[1, 2, 3, 4, 5]") diff -r 1231dc878600 -r c2aa34730dc9 Makefile.am --- a/Makefile.am Wed Aug 10 10:21:22 2016 -0700 +++ b/Makefile.am Thu Aug 11 16:12:35 2016 -0700 @@ -30,6 +30,7 @@ COMMON_SOURCE_FILES = \ exceptions.cc \ octave_to_python.cc \ + oct-py-types.cc \ python_to_octave.cc \ pytave_utils.cc @@ -48,6 +49,7 @@ arrayobjectdefs.h \ config.h \ exceptions.h \ + oct-py-types.h \ octave_to_python.h \ python_to_octave.h \ pytave_utils.h diff -r 1231dc878600 -r c2aa34730dc9 oct-py-types.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oct-py-types.cc Thu Aug 11 16:12:35 2016 -0700 @@ -0,0 +1,67 @@ +/* + +Copyright (C) 2016 Mike Miller + +This file is part of Pytave. + +Pytave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Pytave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Pytave; see the file COPYING. If not, see +. + +*/ + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include + +#include "oct-py-types.h" + +// FIXME: only here to bootstrap nested conversions needed in this file +#include "octave_to_python.h" + +namespace pytave +{ + +inline PyObject * +wrap_octvalue_to_pyobj (const octave_value& value) +{ + boost::python::object obj; + octvalue_to_pyobj (obj, value); + PyObject *ptr = obj.ptr (); + Py_INCREF (ptr); + return ptr; +} + +PyObject * +make_py_dict (const octave_scalar_map& map) +{ + PyObject *dict = PyDict_New (); + if (! dict) + octave_throw_bad_alloc (); + + for (auto p = map.begin (); p != map.end (); ++p) + { + PyObject *key = wrap_octvalue_to_pyobj (map.key (p)); + PyObject *item = wrap_octvalue_to_pyobj (map.contents (p)); + + if (PyDict_SetItem (dict, key, item) < 0) + throw boost::python::error_already_set (); + } + + return dict; +} + +} diff -r 1231dc878600 -r c2aa34730dc9 oct-py-types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oct-py-types.h Thu Aug 11 16:12:35 2016 -0700 @@ -0,0 +1,38 @@ +/* + +Copyright (C) 2016 Mike Miller + +This file is part of Pytave. + +Pytave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Pytave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Pytave; see the file COPYING. If not, see +. + +*/ + +#if ! defined (pytave_oct_py_types_h) +#define pytave_oct_py_types_h 1 + +#include + +class octave_scalar_map; + +namespace pytave +{ + +PyObject * +make_py_dict (const octave_scalar_map& map); + +} + +#endif diff -r 1231dc878600 -r c2aa34730dc9 octave_to_python.cc --- a/octave_to_python.cc Wed Aug 10 10:21:22 2016 -0700 +++ b/octave_to_python.cc Thu Aug 11 16:12:35 2016 -0700 @@ -37,6 +37,7 @@ #include "arrayobjectdefs.h" #include "exceptions.h" #include "octave_to_python.h" +#include "oct-py-types.h" using namespace boost::python; @@ -332,8 +333,11 @@ else if (octvalue.is_numeric_type () || octvalue.is_string () || octvalue.is_bool_type ()) octvalue_to_pyarr (py_object, octvalue); - else if (octvalue.is_map ()) - octmap_to_pyobject (py_object, octvalue.map_value ()); + else if (octvalue.is_map () && octvalue.numel () == 1) + { + PyObject *obj = make_py_dict (octvalue.scalar_map_value ()); + py_object = object (handle (obj)); + } else if (octvalue.is_object () && octvalue.class_name () == "pyobject") { octave_value_list tmp = feval ("getid", ovl (octvalue), 1);