changeset 330:5c63651b0ec4

Merged in genuinelucifer/pytave_main (pull request #40) Add isequal method to allow comparing pyobjects (fixes issue #53)
author Mike Miller <mtmiller@octave.org>
date Sat, 13 Aug 2016 23:59:49 -0700
parents 5782d7932529 (diff) 778c91283a73 (current diff)
children cee203ea6245
files @pyobject/pyobject.m
diffstat 12 files changed, 197 insertions(+), 307 deletions(-) [+]
line wrap: on
line diff
--- a/@py/py.m	Fri Aug 12 05:45:06 2016 -0700
+++ b/@py/py.m	Sat Aug 13 23:59:49 2016 -0700
@@ -28,3 +28,27 @@
 
 %!assert (py.math.sqrt (2), sqrt (2))
 %!assert (ischar (py.sys.version))
+
+%!test
+%! if (double (py.sys.hexversion) >= 0x03000000)
+%!   assert (isobject (py.int (0)))
+%! else
+%!   assert (py.int (0), int64 (0))
+%! endif
+
+%!test
+%! if (double (py.sys.hexversion) < 0x03000000)
+%!   assert (py.int (2147483647), int64 (2147483647))
+%! endif
+
+%!test
+%! if (double (py.sys.hexversion) < 0x03000000)
+%!   assert (isobject (py.long (0)))
+%! endif
+
+%!test
+%! if (double (py.sys.hexversion) >= 0x03000000)
+%!   assert (isobject (py.int (2^100)))
+%! else
+%!   assert (isobject (py.long (2^100)))
+%! endif
--- a/@pyobject/cell.m	Fri Aug 12 05:45:06 2016 -0700
+++ b/@pyobject/cell.m	Sat Aug 13 23:59:49 2016 -0700
@@ -27,10 +27,10 @@
 ## converted into native Octave objects:
 ## @example
 ## @group
-## L = pyeval ("[10, 20, 'hello']")
+## L = pyeval ("[10.0, 20.0, 'hello']")
 ##   @result{} L = [pyobject ...]
 ##
-##       [10, 20, 'hello']
+##       [10.0, 20.0, 'hello']
 ## @end group
 ## @end example
 ##
@@ -50,7 +50,7 @@
 ## The conversion is not recursive, in the following sense:
 ## @example
 ## @group
-## L = pyeval ("[10, 20, [33, 44], 50]");
+## L = pyeval ("[10.0, 20.0, [33.0, 44.0], 50.0]");
 ## C = cell (L)
 ##   @result{} C =
 ##     @{
@@ -58,7 +58,7 @@
 ##       [1,2] =  20
 ##             = [pyobject ...]
 ##
-##                 [33, 44]
+##                 [33.0, 44.0]
 ##
 ##       [1,4] =  50
 ##     @}
@@ -81,11 +81,15 @@
 
 
 %!assert (cell (pyeval ("[]")), cell (1, 0))
-%!assert (cell (pyeval ("[1]")), {1})
-%!assert (cell (pyeval ("[1, 2, 3]")), {1, 2, 3})
-%!assert (cell (pyeval ("(1, 2, 3)")), {1, 2, 3})
+%!assert (cell (pyeval ("[1.]")), {1})
+%!assert (cell (pyeval ("[1., 2., 3.]")), {1, 2, 3})
+%!assert (cell (pyeval ("(1., 2., 3.)")), {1, 2, 3})
 %!assert (cell (pyobject ("asdf")), {"a", "s", "d", "f"})
-%!assert (cell (pyeval ("range(10)")), num2cell (0:9))
+
+%!test
+%! c = cell (pyeval ("range(10)"));
+%! c = cellfun (@(x) eval ("double (x)"), c, "uniformoutput", false);
+%! assert (c, num2cell (0:9))
 
 %!error cell (pyobject ())
 %!error cell (pyeval ("None"))
--- a/@pyobject/dummy.m	Fri Aug 12 05:45:06 2016 -0700
+++ b/@pyobject/dummy.m	Sat Aug 13 23:59:49 2016 -0700
@@ -25,7 +25,7 @@
 ## Some simple Python objects are converted to equivalent Octave values:
 ## @example
 ## @group
-## pyeval ("6")
+## pyeval ("6.0")
 ##   @result{} ans = 6
 ## @end group
 ## @end example
@@ -54,9 +54,9 @@
 ##       [4,1] = real
 ##     @}
 ##
-## g.numerator
+## double (g.numerator)
 ##   @result{} ans =  6
-## g.denominator
+## double (g.denominator)
 ##   @result{} ans =  1
 ## @end group
 ## @end example
@@ -83,7 +83,7 @@
 ## We can accesss ``callables'' (methods) of objects:
 ## @example
 ## @group
-## x.pop ("two")
+## double (x.pop ("two"))
 ##   @result{} ans =  2
 ## @end group
 ## @end example
@@ -120,9 +120,9 @@
 ## A Python list is returned as a @@pyobject:
 ## @example
 ## @group
-## L = pyeval ("[42, 'hello', sys]")
+## L = pyeval ("[42.0, 'hello', sys]")
 ##   @result{} L = [pyobject ...]
-##       [42, 'hello', <module 'sys' (built-in)>]
+##       [42.0, 'hello', <module 'sys' (built-in)>]
 ## @end group
 ## @end example
 ##
--- a/@pyobject/pyobject.m	Fri Aug 12 05:45:06 2016 -0700
+++ b/@pyobject/pyobject.m	Sat Aug 13 23:59:49 2016 -0700
@@ -151,7 +151,7 @@
 
     function len = length (x)
       try
-        len = pycall ("len", x);
+        len = double (pycall ("len", x));
       catch
         len = 1;
       end_try_catch
@@ -163,7 +163,7 @@
       try
         idx = struct ("type", ".", "subs", "shape");
         sz = subsref (x, idx);
-        sz = cell2mat (cell (sz));
+        sz = cellfun (@(x) eval ("double (x)"), cell (sz));
       catch
         ## if it had no shape, make it a row vector
         sz = [1 length(x)];
@@ -265,15 +265,15 @@
 
 %!test
 %! L = pyeval ("[10, 20, 30]");
-%! assert (L{end}, 30)
-%! assert (L{end-1}, 20)
+%! assert (double (L{end}), 30)
+%! assert (double (L{end-1}), 20)
 
 %!test
 %! % ensure "end" works for iterables that are not lists
 %! myrange = pyeval ( ...
 %!   "range if __import__('sys').hexversion >= 0x03000000 else xrange");
 %! R = pycall (myrange, int32 (5), int32 (10), int32 (2));
-%! assert (R{end}, 9)
+%! assert (double (R{end}), 9)
 
 %!shared a
 %! pyexec ("class _myclass(): shape = (3, 4, 5)")
--- a/@pyobject/subsasgn.m	Fri Aug 12 05:45:06 2016 -0700
+++ b/@pyobject/subsasgn.m	Sat Aug 13 23:59:49 2016 -0700
@@ -88,7 +88,7 @@
 
 %!test
 %! % list indexing
-%! L = pyeval ("[10, 20]");
+%! L = pyeval ("[10., 20.]");
 %! L{2} = "Octave";
 %! assert (length (L) == 2)
 %! assert (L{1}, 10)
--- a/@pyobject/subsref.m	Fri Aug 12 05:45:06 2016 -0700
+++ b/@pyobject/subsref.m	Sat Aug 13 23:59:49 2016 -0700
@@ -114,13 +114,13 @@
 
 %!test
 %! % list indexing
-%! L = pyeval ("[10, 20]");
+%! L = pyeval ("[10., 20.]");
 %! assert (L{1}, 10)
 %! assert (L{2}, 20)
 
 %!test
 %! % list indexing, slice
-%! L = pyeval ("[10, 20, [30, 40]]");
+%! L = pyeval ("[10., 20., [30., 40.]]");
 %! L2 = L{:};
 %! assert (L2{1}, 10)
 %! assert (L2{2}, 20)
@@ -129,14 +129,14 @@
 
 %!test
 %! % list indexing, nested list
-%! L = pyeval ("[1, 2, [10, 11, 12]]");
+%! L = pyeval ("[1., 2., [10., 11., 12.]]");
 %! assert (L{2}, 2)
 %! assert (L{3}{1}, 10)
 %! assert (L{3}{3}, 12)
 
 %!test
 %! % list indexing, assign to vars
-%! L = pyeval ("[1, 2, 'Octave']");
+%! L = pyeval ("[1., 2., 'Octave']");
 %! [a, b, c] = L{:};
 %! assert (a, 1)
 %! assert (b, 2)
@@ -144,7 +144,7 @@
 
 %!test
 %! % 2D array indexing
-%! A = pyobject ([1 2; 3 4]);
+%! A = pyobject ([1. 2.; 3. 4.]);
 %! assert (A{1, 1}, 1)
 %! assert (A{2, 1}, 3)
 %! assert (A{1, 2}, 2)
@@ -158,17 +158,17 @@
 
 %!test
 %! % dict: str key access
-%! d = pyeval ("{'one':1, 5:5, 6:6}");
+%! d = pyeval ("{'one':1., 5:5, 6:6}");
 %! assert (d{"one"}, 1)
 
 %!test
 %! % dict: integer key access
-%! d = pyeval ("{5:42, 6:42}");
+%! d = pyeval ("{5:42., 6:42.}");
 %! assert (d{6}, 42)
 
 %!test
 %! % dict: integer key should not subtract one
-%! d = pyeval ("{5:40, 6:42}");
+%! d = pyeval ("{5:40., 6:42.}");
 %! assert (d{6}, 42)
 
 %!test
@@ -178,7 +178,7 @@
 
 %!test
 %! % dict: make sure key ":" doesn't break anything
-%! d = pyeval ("{'a':1, ':':2}");
+%! d = pyeval ("{'a':1., ':':2.}");
 %! assert (d{'a'}, 1)
 %! assert (d{':'}, 2)
 
@@ -199,7 +199,7 @@
 
 %!test
 %! % callable can return something
-%! s = pyeval ("set({1, 2})");
+%! s = pyeval ("set({1., 2.})");
 %! v = s.pop ();
 %! assert (length (s) == 1)
 %! assert (v == 1 || v == 2)
@@ -235,7 +235,7 @@
 
 %!test
 %! % multiple return values: separate them
-%! f = pyeval ("lambda: (1, 2, 3)");
+%! f = pyeval ("lambda: (1., 2., 3.)");
 %! [a, b, c] = f ();
 %! assert (a, 1)
 %! assert (b, 2)
--- a/oct-py-types.cc	Fri Aug 12 05:45:06 2016 -0700
+++ b/oct-py-types.cc	Sat Aug 13 23:59:49 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,65 @@
   return dict;
 }
 
+int64_t
+extract_py_int64 (PyObject *obj)
+{
+  if (! obj)
+    throw object_convert_exception ("failed to extract integer: null object");
+
+  if (PyLong_Check (obj))
+    return PyLong_AsLong (obj);
+#if PY_VERSION_HEX < 0x03000000
+  else if (PyInt_Check (obj))
+    return PyInt_AsLong (obj);
+#endif
+  else
+    throw object_convert_exception ("failed to extract integer: wrong type");
+
+  return 0;
 }
+
+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 05:45:06 2016 -0700
+++ b/oct-py-types.h	Sat Aug 13 23:59:49 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,15 @@
 PyObject *
 make_py_dict (const octave_scalar_map& map);
 
+int64_t
+extract_py_int64 (PyObject *obj);
+
+std::string
+extract_py_str (PyObject *obj);
+
+PyObject *
+make_py_str (const std::string& str);
+
 }
 
 #endif
--- a/octave_to_python.cc	Fri Aug 12 05:45:06 2016 -0700
+++ b/octave_to_python.cc	Sat Aug 13 23:59:49 2016 -0700
@@ -76,43 +76,6 @@
       }
   }
 
-  template <>
-  void
-  copy_octarray_to_pyarrobj<PyObject *, Cell> (PyArrayObject *pyarr,
-                                               const Cell& matrix,
-                                               const unsigned int matindex,
-                                               const unsigned int matstride,
-                                               const int dimension,
-                                               const unsigned int offset)
-  {
-    unsigned char *ptr = (unsigned char*) PyArray_DATA (pyarr);
-    if (dimension == PyArray_NDIM (pyarr) - 1)
-      {
-        // Last dimension, base case
-        for (int i = 0; i < PyArray_DIM (pyarr, dimension); i++)
-          {
-            object pyobj;
-            octvalue_to_pyobj (pyobj, matrix.elem (matindex + i*matstride));
-            Py_INCREF (pyobj.ptr ());
-            *(PyObject **)&ptr[offset + i*PyArray_STRIDE (pyarr, dimension)]
-                = pyobj.ptr ();
-          }
-      }
-    else
-      {
-        for (int i = 0; i < PyArray_DIM (pyarr, dimension); i++)
-          {
-            copy_octarray_to_pyarrobj<PyObject *, Cell> (
-              pyarr,
-              matrix,
-              matindex + i*matstride,
-              matstride * PyArray_DIM (pyarr, dimension),
-              dimension + 1,
-              offset + i*PyArray_STRIDE (pyarr, dimension));
-          }
-      }
-  }
-
   static PyArrayObject *
   createPyArr (const dim_vector& dims, int pyarrtype)
   {
@@ -214,22 +177,6 @@
     py_object = sequence;
   }
 
-  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.numel (); i++)
-      {
-        boost::python::object py_val;
-        const Cell c = map.contents (keys[i]);
-        octvalue_to_pyarr (py_val, c);
-        py_object[keys[i]] = py_val;
-      }
-  }
-
   inline PyObject *
   python_integer_value (int32_t value)
   {
@@ -305,19 +252,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 +259,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/pycall.cc	Fri Aug 12 05:45:06 2016 -0700
+++ b/pycall.cc	Sat Aug 13 23:59:49 2016 -0700
@@ -49,7 +49,7 @@
 Examples:\n\
 @example\n\
 @group\n\
-pycall (\"int\", 6)\n\
+pycall (\"float\", 6)\n\
   @result{} 6\n\
 pycall (\"os.getuid\")\n\
   @result{} ...\n\
@@ -142,11 +142,11 @@
 /*
 %!assert (ischar (pycall ("os.getcwd")))
 %!assert (isreal (pycall ("random.random")))
-%!assert (pycall ("math.exp", 3), exp (3))
-%!assert (pycall ("math.trunc", pi), fix (pi))
-%!assert (pycall ("math.sqrt", 2), sqrt (2))
-%!assert (pycall ("cmath.sqrt", 2j), sqrt (2j))
-%!assert (pycall ("int", 10.2), 10)
+%!assert (double (pycall ("math.exp", 3)), exp (3))
+%!assert (double (pycall ("math.trunc", pi)), fix (pi))
+%!assert (double (pycall ("math.sqrt", 2)), sqrt (2))
+%!assert (double (pycall ("cmath.sqrt", 2j)), sqrt (2j))
+%!assert (double (pycall ("int", 10.2)), 10)
 %!assert (isa (pycall ("object"), "pyobject"))
 %!assert (isa (pycall ("dict"), "pyobject"))
 %!assert (isa (pycall ("list"), "pyobject"))
@@ -215,6 +215,28 @@
 %! pyexec ("def intwrapper(x): return int(x)");
 %! pycall ("intwrapper", ftp ());
 
+## Test conversion of integer types from Python
+%!test
+%! if (pyeval ("__import__('sys').hexversion >= 0x03000000"))
+%!   assert (isa (pycall ("int",  0), "pyobject"))
+%!   assert (isa (pycall ("int",  2^31-1), "pyobject"))
+%!   assert (isa (pycall ("int", -2^31), "pyobject"))
+%!   assert (double (pycall ("int",  0)), 0)
+%!   assert (double (pycall ("int",  2^31-1)), 2^31-1)
+%!   assert (double (pycall ("int", -2^31)), -2^31)
+%! else
+%!   assert (pycall ("int",  0), int64 (0))
+%!   assert (pycall ("int",  2^31-1), int64 (2^31-1))
+%!   assert (pycall ("int", -2^31), int64 (-2^31))
+%!   assert (isa (pycall ("long",  0), "pyobject"))
+%!   assert (isa (pycall ("long",  2^31-1), "pyobject"))
+%!   assert (isa (pycall ("long", -2^31), "pyobject"))
+%!   assert (double (pycall ("long",  0)), 0)
+%!   assert (double (pycall ("long",  2^31-1)), 2^31-1)
+%!   assert (double (pycall ("long", -2^31)), -2^31)
+%! endif
+%!assert (isa (pycall ("int", 2^100), "pyobject"))
+
 %!test
 %! pyexec ("def pyfunc(x): return 2*x");
 %! z = pycall ("pyfunc", [20 20]);
@@ -225,9 +247,9 @@
 %!         "    if x is True:\n        return 30\n" ...
 %!         "    elif x is False:\n        return 20\n" ...
 %!         "    else:\n        return 10"]);
-%! assert (pycall ("pyfunc", true), 30)
-%! assert (pycall ("pyfunc", false), 20)
-%! assert (pycall ("pyfunc", 10), 10)
+%! assert (double (pycall ("pyfunc", true)), 30)
+%! assert (double (pycall ("pyfunc", false)), 20)
+%! assert (double (pycall ("pyfunc", 10)), 10)
 
 %!error <NameError>
 %! pyexec ("def raiseException(): raise NameError('oops')")
--- a/pyeval.cc	Fri Aug 12 05:45:06 2016 -0700
+++ b/pyeval.cc	Sat Aug 13 23:59:49 2016 -0700
@@ -118,9 +118,9 @@
 }
 
 /*
-%!assert (isnumeric (pyeval ("0")))
-%!assert (isreal (pyeval ("0")))
-%!assert (pyeval ("0"), 0)
+%!assert (isnumeric (double (pyeval ("0"))))
+%!assert (isreal (double (pyeval ("0"))))
+%!assert (double (pyeval ("0")), 0)
 
 %!assert (isnumeric (pyeval ("10.1")))
 %!assert (isreal (pyeval ("10.1")))
@@ -142,27 +142,27 @@
 
 %!assert (isa (pyeval ("object()"), "pyobject"))
 
-%!assert (isnumeric (pyeval ("__import__('sys').maxsize")))
-%!assert (pyeval ("99999999999999"), 99999999999999)
-%!assert (pyeval ("-99999999999999"), -99999999999999)
+%!assert (isnumeric (double (pyeval ("__import__('sys').maxsize"))))
+%!assert (double (pyeval ("99999999999999")), 99999999999999)
+%!assert (double (pyeval ("-99999999999999")), -99999999999999)
 
 %!test
-%! z = pyeval ("{'x': 1, 'y': 2}");
+%! z = pyeval ("{'x': 1., 'y': 2.}");
 %! assert (isa (z, "pyobject"))
 %! assert (z{"x"}, 1)
 
 %!test
-%! z = pyeval ("[1, 2, 3]");
+%! z = pyeval ("[1., 2., 3.]");
 %! assert (isa (z, "pyobject"))
 %! assert ({z{1}, z{2}, z{3}}, {1, 2, 3})
 
 %!test
-%! z = pyeval ("(4, 5, 6)");
+%! z = pyeval ("(4., 5., 6.)");
 %! assert (isa (z, "pyobject"))
 %! assert ({z{1}, z{2}, z{3}}, {4, 5, 6})
 
 %!test
-%! z = pyeval ("[1, [21, 22], 3, [41, [421, 422], 43]]");
+%! z = pyeval ("[1., [21., 22.], 3., [41., [421., 422.], 43.]]");
 %! assert (isa (z, "pyobject"))
 %! assert (isa (z{2}, "pyobject"))
 %! assert (z{2}{1}, 21)
@@ -178,16 +178,16 @@
 %!test
 %! % Variable defined in global namespace is available locally
 %! myNS = pyeval ("{}");
-%! pyexec ("myvar = 1")
+%! pyexec ("myvar = 1.")
 %! assert (pyeval ("myvar", myNS), 1);
 
 %!test
 %! % Variables with same name can have different values in different namespaces
 %! myNS1 = pyeval ("{}");
 %! myNS2 = pyeval ("{}");
-%! pyexec ("myvar = 1")
-%! pyexec ("myvar = 2", myNS1)
-%! pyexec ("myvar = 3", myNS2)
+%! pyexec ("myvar = 1.")
+%! pyexec ("myvar = 2.", myNS1)
+%! pyexec ("myvar = 3.", myNS2)
 %! assert (pyeval ("myvar"), 1)
 %! assert (pyeval ("myvar", myNS1), 2)
 %! assert (pyeval ("myvar", myNS2), 3)
@@ -196,14 +196,14 @@
 %! pyexec ("if 'myvar' in globals(): del myvar")
 %! % Namespaces can also be passed as strings
 %! pyexec ("myNS = {}");
-%! pyexec ("myvar = 1", "myNS");
+%! pyexec ("myvar = 1.", "myNS");
 %! assert (pyeval ("myvar", "myNS"), 1);
 
 %!error <NameError>
 %! pyexec ("if 'myvar' in globals(): del myvar")
 %! % Variable defined in local namespace MUST not be available globally
 %! myNS = pyeval ("{}");
-%! pyexec ("myvar = 1", myNS)
+%! pyexec ("myvar = 1.", myNS)
 %! pyeval ("myvar");
 
 %!error <NameError>
@@ -211,7 +211,7 @@
 %! % Variable defined in one local namespace MUST not be available in another
 %! myNS1 = pyeval ("{}");
 %! myNS2 = pyeval ("{}");
-%! pyexec ("myvar = 1", myNS1)
+%! pyexec ("myvar = 1.", myNS1)
 %! pyeval ("myvar", myNS2);
 
 %!error <NameError>
--- a/python_to_octave.cc	Fri Aug 12 05:45:06 2016 -0700
+++ b/python_to_octave.cc	Sat Aug 13 23:59:49 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"
 
@@ -84,48 +85,6 @@
       }
   }
 
-  template <>
-  void
-  copy_pyarrobj_to_octarray<PyObject *, Cell> (Cell& matrix,
-                                               PyArrayObject *pyarr,
-                                               const int unsigned matindex,
-                                               const unsigned int matstride,
-                                               const int dimension,
-                                               const unsigned int offset)
-  {
-    unsigned char *ptr = (unsigned char*) PyArray_DATA (pyarr);
-    if (dimension == PyArray_NDIM (pyarr) - 1)
-      {
-        // Last dimension, base case
-        for (int i = 0; i < PyArray_DIM (pyarr, dimension); i++)
-          {
-            PyObject *pobj = *(PyObject **)
-               &ptr[offset + i*PyArray_STRIDE (pyarr, dimension)];
-            pyobj_to_octvalue (matrix.elem (matindex + i*matstride),
-                               object (handle<PyObject> (borrowed (pobj))));
-          }
-      }
-    else if (PyArray_NDIM (pyarr) == 0)
-      {
-        PyObject *pobj = *(PyObject **) ptr;
-        pyobj_to_octvalue (matrix.elem (0),
-                           object (handle<PyObject> (borrowed (pobj))));
-      }
-    else
-      {
-        for (int i = 0; i < PyArray_DIM (pyarr, dimension); i++)
-          {
-            copy_pyarrobj_to_octarray<PyObject *, Cell> (
-              matrix,
-              pyarr,
-              matindex + i*matstride,
-              matstride * PyArray_DIM (pyarr, dimension),
-              dimension + 1,
-              offset + i*PyArray_STRIDE (pyarr, dimension));
-          }
-      }
-  }
-
   template <class PythonPrimitive, class OctaveBase>
   static void
   copy_pyarrobj_to_octarray_dispatch (OctaveBase& matrix,
@@ -217,7 +176,6 @@
       ARRAYCASE (NPY_BOOL,    bool)
       ARRAYCASE (NPY_CHAR,    char)
       ARRAYCASE (NPY_STRING,  char)
-      ARRAYCASE (NPY_OBJECT,  PyObject *)
 
       default:
         throw object_convert_exception (
@@ -343,9 +301,6 @@
             }
         }
         break;
-      case NPY_OBJECT:
-        pyarrobj_to_octvalueNd<Cell> (octvalue, pyarr, dims);
-        break;
       default:
         throw object_convert_exception (
           PyEval_GetFuncDesc ((PyObject*)(pyarr)) + std::string (" ")
@@ -356,127 +311,6 @@
   }
 
   static void
-  pylist_to_cellarray (octave_value& oct_value, const boost::python::list& list)
-  {
-    octave_idx_type length = boost::python::extract<octave_idx_type> (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
-  pytuple_to_cellarray (octave_value& oct_value, const boost::python::tuple& tuple)
-  {
-    octave_idx_type length = boost::python::extract<octave_idx_type> (tuple.attr ("__len__") ());
-    octave_value_list values;
-
-    for (octave_idx_type i = 0; i < length; i++)
-      {
-         octave_value val;
-
-         pyobj_to_octvalue (val, tuple[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 ();
-    octave_idx_type length = boost::python::extract<octave_idx_type> (list.attr ("__len__") ());
-
-    dim_vector dims = dim_vector (1, 1);
-
-    octave_value_list vals (length);
-    string_vector keys (length);
-
-    // Extract all keys and convert values. Remember whether dimensions
-    // match.
-
-    for (octave_idx_type i = 0; i < length; i++)
-      {
-        std::string& key = keys[i];
-
-        boost::python::tuple tuple =
-            boost::python::extract<boost::python::tuple> (list[i]) ();
-
-        boost::python::extract<std::string> str (tuple[0]);
-        if (! str.check ())
-          throw object_convert_exception (
-            std::string ("Can not convert key of type ")
-            + PyEval_GetFuncName (boost::python::object (tuple[0]).ptr ())
-            + PyEval_GetFuncDesc (boost::python::object (tuple[0]).ptr ())
-            + " to a structure field name. Field names must be strings.");
-
-        key = str ();
-
-        if (! valid_identifier (key))
-          throw object_convert_exception (
-            std::string ("Can not convert key `") + key + "' to a structure "
-            "field name. Field names must be valid Octave identifiers.");
-
-        octave_value& val = vals(i);
-
-        pyobj_to_octvalue (val, tuple[1]);
-
-        if (val.is_cell ())
-          {
-            if (i == 0)
-               dims = val.dims ();
-            else if (val.numel () != 1 && val.dims () != dims)
-               throw object_convert_exception (
-                 "Dimensions of the struct fields do not match");
-          }
-      }
-
-    octave_map map = octave_map (dims);
-
-    for (octave_idx_type i = 0; i < length; i++)
-      {
-        std::string& key = keys[i];
-        octave_value val = vals(i);
-
-        if (val.is_cell ())
-         {
-            const Cell c = val.cell_value ();
-            if (c.numel () == 1)
-            {
-               map.assign (key, Cell (dims, c(0)));
-            }
-            else
-            {
-               map.assign (key, c);
-            }
-         }
-        else
-          map.assign (key, Cell (dims, val));
-      }
-    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)
   {
@@ -504,31 +338,25 @@
   void pyobj_to_octvalue (octave_value& oct_value,
                           const boost::python::object& py_object)
   {
-    extract<long> longx (py_object);
     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);
-    extract<boost::python::tuple> tuplex (py_object);
 
-    if (boolx.check () && PyBool_Check ((PyArrayObject*)py_object.ptr ()))
+    if (PyBool_Check (py_object.ptr ()))
       oct_value = boolx ();
-    else if (longx.check ())
-      oct_value = longx ();
-    else if (doublex.check ())
+#if PY_VERSION_HEX < 0x03000000
+    else if (PyInt_Check (py_object.ptr ()))
+      oct_value = octave_int64 (extract_py_int64 (py_object.ptr ()));
+#endif
+    else if (PyFloat_Check (py_object.ptr ()))
       oct_value = doublex ();
-    else if (complexx.check ())
+    else if (PyComplex_Check (py_object.ptr ()))
       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);
   }