changeset 325:fd5881d48238

Overhaul Python string creation and extraction * oct-py-types.cc, oct-py-types.h (pytave::extract_py_str, pytave::make_py_str): New functions to create a Python string and extract string value from Python. (pytave::make_py_dict): Use make_py_str. * octave_to_python.cc (pytave::octvalue_to_pyobj): Use make_py_str. (pytave::octstring_to_pyobject): Delete. * python_to_octave.cc (pytave::pyobj_to_octvalue): Use extract_py_str. (pytave::pyunicode_to_utf8): Delete.
author Mike Miller <mtmiller@octave.org>
date Sat, 13 Aug 2016 19:29:47 -0700
parents 2b2460295218
children 37df9bd607ed
files oct-py-types.cc oct-py-types.h octave_to_python.cc python_to_octave.cc
diffstat 4 files changed, 62 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/oct-py-types.cc	Fri Aug 12 00:57:46 2016 -0700
+++ b/oct-py-types.cc	Sat Aug 13 19:29:47 2016 -0700
@@ -27,6 +27,7 @@
 #include <octave/oct-map.h>
 #include <octave/quit.h>
 
+#include "exceptions.h"
 #include "oct-py-types.h"
 
 // FIXME: only here to bootstrap nested conversions needed in this file
@@ -54,7 +55,10 @@
 
   for (auto p = map.begin (); p != map.end (); ++p)
     {
-      PyObject *key = wrap_octvalue_to_pyobj (map.key (p));
+      PyObject *key = make_py_str (map.key (p));
+      if (! key)
+        octave_throw_bad_alloc ();
+
       PyObject *item = wrap_octvalue_to_pyobj (map.contents (p));
 
       if (PyDict_SetItem (dict, key, item) < 0)
@@ -64,4 +68,47 @@
   return dict;
 }
 
+std::string
+extract_py_str (PyObject *obj)
+{
+  std::string retval;
+
+  if (! obj)
+    throw object_convert_exception ("failed to extract string: null object");
+  if (PyBytes_Check (obj))
+    {
+      retval.assign (PyBytes_AsString (obj), PyBytes_Size (obj));
+    }
+  else if (PyUnicode_Check (obj))
+    {
+      bool ok = false;
+      PyObject *enc = PyUnicode_AsUTF8String (obj);
+      if (enc)
+        {
+          if (PyBytes_Check (enc))
+            {
+              ok = true;
+              retval.assign (PyBytes_AsString (enc), PyBytes_Size (enc));
+            }
+          Py_DECREF (enc);
+        }
+      if (! ok)
+        throw object_convert_exception ("failed to extract string: UTF-8 error");
+    }
+  else
+    throw object_convert_exception ("failed to extract string: wrong type");
+
+  return retval;
 }
+
+PyObject *
+make_py_str (const std::string& str)
+{
+#if PY_VERSION_HEX >= 0x03000000
+  return PyUnicode_FromStringAndSize (str.data (), str.size ());
+#else
+  return PyString_FromStringAndSize (str.data (), str.size ());
+#endif
+}
+
+}
--- a/oct-py-types.h	Fri Aug 12 00:57:46 2016 -0700
+++ b/oct-py-types.h	Sat Aug 13 19:29:47 2016 -0700
@@ -24,6 +24,7 @@
 #define pytave_oct_py_types_h 1
 
 #include <Python.h>
+#include <string>
 
 class octave_scalar_map;
 
@@ -33,6 +34,12 @@
 PyObject *
 make_py_dict (const octave_scalar_map& map);
 
+std::string
+extract_py_str (PyObject *obj);
+
+PyObject *
+make_py_str (const std::string& str);
+
 }
 
 #endif
--- a/octave_to_python.cc	Fri Aug 12 00:57:46 2016 -0700
+++ b/octave_to_python.cc	Sat Aug 13 19:29:47 2016 -0700
@@ -305,19 +305,6 @@
       throw value_convert_exception ("unhandled scalar type");
   }
 
-  static void
-  octstring_to_pyobject (boost::python::object& py_object,
-                         const std::string& str)
-  {
-    py_object = object (handle<PyObject> (
-#if PY_VERSION_HEX >= 0x03000000
-      PyUnicode_FromStringAndSize (str.data (), str.size ())
-#else
-      PyString_FromStringAndSize (str.data (), str.size ())
-#endif
-    ));
-  }
-
   void octvalue_to_pyobj (boost::python::object& py_object,
                           const octave_value& octvalue)
   {
@@ -325,7 +312,10 @@
       throw value_convert_exception (
         "Octave value `undefined'. Can not convert to a Python object");
     else if (octvalue.is_string ())
-      octstring_to_pyobject (py_object, octvalue.string_value ());
+      {
+        PyObject *obj = make_py_str (octvalue.string_value ());
+        py_object = object (handle<PyObject> (obj));
+      }
     else if (octvalue.is_scalar_type ())
       octscalar_to_pyobject (py_object, octvalue);
     else if (octvalue.is_cell ())
--- a/python_to_octave.cc	Fri Aug 12 00:57:46 2016 -0700
+++ b/python_to_octave.cc	Sat Aug 13 19:29:47 2016 -0700
@@ -40,6 +40,7 @@
 
 #include "arrayobjectdefs.h"
 #include "exceptions.h"
+#include "oct-py-types.h"
 #include "python_to_octave.h"
 #include "pytave_utils.h"
 
@@ -466,16 +467,6 @@
     oct_value = map;
   }
 
-  static std::string
-  pyunicode_to_utf8 (PyObject *unicode)
-  {
-    std::string str;
-    PyObject *utf8 = PyUnicode_AsUTF8String (unicode);
-    str.assign (PyBytes_AsString (utf8), PyBytes_Size (utf8));
-    Py_DECREF (utf8);
-    return str;
-  }
-
   static void
   pyobj_to_oct_pyobject (octave_value& oct_value,
                          const boost::python::object& py_object)
@@ -508,8 +499,6 @@
     extract<bool> boolx (py_object);
     extract<double> doublex (py_object);
     extract<Complex> complexx (py_object);
-    extract<std::string> stringx (py_object);
-    extract<std::wstring> wstringx (py_object);
     extract<numeric::array> arrayx (py_object);
     extract<boost::python::list> listx (py_object);
     extract<boost::python::dict> dictx (py_object);
@@ -525,10 +514,8 @@
       oct_value = complexx ();
     else if (arrayx.check ())
       pyarr_to_octvalue (oct_value, (PyArrayObject*)py_object.ptr ());
-    else if (stringx.check ())
-      oct_value = stringx ();
-    else if (wstringx.check ())
-      oct_value = pyunicode_to_utf8 (py_object.ptr ());
+    else if (PyBytes_Check (py_object.ptr ()) || PyUnicode_Check (py_object.ptr ()))
+      oct_value = extract_py_str (py_object.ptr ());
     else
       pyobj_to_oct_pyobject (oct_value, py_object);
   }