changeset 328:5782d7932529

Automatically convert Python 2 'int' type to Octave int64 (fixes issue #56) * oct-py-types.cc, oct-py-types.h (pytave::extract_py_int64): New function. * python_to_octave.cc (pytave::pyobj_to_octvalue): Convert Python 2 'int' to Octave int64 type. * @py/py.m, pycall.cc: Add %!tests for Python 'int' and 'long' type handling, conditional on Python version.
author Mike Miller <mtmiller@octave.org>
date Sat, 13 Aug 2016 23:52:57 -0700
parents 15c20ab4b80a
children 5c63651b0ec4
files @py/py.m oct-py-types.cc oct-py-types.h pycall.cc python_to_octave.cc
diffstat 5 files changed, 71 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/@py/py.m	Sat Aug 13 21:24:29 2016 -0700
+++ b/@py/py.m	Sat Aug 13 23:52:57 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/oct-py-types.cc	Sat Aug 13 21:24:29 2016 -0700
+++ b/oct-py-types.cc	Sat Aug 13 23:52:57 2016 -0700
@@ -68,6 +68,24 @@
   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)
 {
--- a/oct-py-types.h	Sat Aug 13 21:24:29 2016 -0700
+++ b/oct-py-types.h	Sat Aug 13 23:52:57 2016 -0700
@@ -34,6 +34,9 @@
 PyObject *
 make_py_dict (const octave_scalar_map& map);
 
+int64_t
+extract_py_int64 (PyObject *obj);
+
 std::string
 extract_py_str (PyObject *obj);
 
--- a/pycall.cc	Sat Aug 13 21:24:29 2016 -0700
+++ b/pycall.cc	Sat Aug 13 23:52:57 2016 -0700
@@ -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]);
--- a/python_to_octave.cc	Sat Aug 13 21:24:29 2016 -0700
+++ b/python_to_octave.cc	Sat Aug 13 23:52:57 2016 -0700
@@ -345,6 +345,10 @@
 
     if (PyBool_Check (py_object.ptr ()))
       oct_value = boolx ();
+#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 (PyComplex_Check (py_object.ptr ()))