changeset 327:15c20ab4b80a

Do not automatically convert Python integer types to Octave (see issue #56) * python_to_octave.cc (pytave::pyobj_to_octvalue): Drop automatic conversion of Python int and long types to Octave. * @pyobject/pyobject.m (pyobject.length, pyobject.size): Cast values to double. Adapt %!tests to changes. * @pyobject/cell.m, @pyobject/dummy.m, @pyobject/subsasgn.m, @pyobject/subsref.m, pycall.cc, pyeval.cc: Adapt usage examples and %!tests to changes.
author Mike Miller <mtmiller@octave.org>
date Sat, 13 Aug 2016 21:24:29 -0700
parents 37df9bd607ed
children 5782d7932529
files @pyobject/cell.m @pyobject/dummy.m @pyobject/pyobject.m @pyobject/subsasgn.m @pyobject/subsref.m pycall.cc pyeval.cc python_to_octave.cc
diffstat 8 files changed, 64 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/@pyobject/cell.m	Sat Aug 13 19:57:49 2016 -0700
+++ b/@pyobject/cell.m	Sat Aug 13 21:24:29 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	Sat Aug 13 19:57:49 2016 -0700
+++ b/@pyobject/dummy.m	Sat Aug 13 21:24:29 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	Sat Aug 13 19:57:49 2016 -0700
+++ b/@pyobject/pyobject.m	Sat Aug 13 21:24:29 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)];
@@ -254,15 +254,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	Sat Aug 13 19:57:49 2016 -0700
+++ b/@pyobject/subsasgn.m	Sat Aug 13 21:24:29 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	Sat Aug 13 19:57:49 2016 -0700
+++ b/@pyobject/subsref.m	Sat Aug 13 21:24:29 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/pycall.cc	Sat Aug 13 19:57:49 2016 -0700
+++ b/pycall.cc	Sat Aug 13 21:24:29 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"))
@@ -225,9 +225,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	Sat Aug 13 19:57:49 2016 -0700
+++ b/pyeval.cc	Sat Aug 13 21:24:29 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	Sat Aug 13 19:57:49 2016 -0700
+++ b/python_to_octave.cc	Sat Aug 13 21:24:29 2016 -0700
@@ -338,19 +338,16 @@
   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<numeric::array> arrayx (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 ())
+    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 ());