changeset 282:4c4747646e12

Make pyobject callable by users (to convert input) This makes "pyobject(...)" behave more a cast or typical constructor call. This should supercede the "fromPythonVarName" hack in some cases. * @pyobject/dummy.m: Use new pyobject call. * @pyobject/pyobject.m (@pyobject/pyobject): Redo ctor. * python_to_octave.cc: Use new pyobject ctor.
author Colin Macdonald <cbm@m.fsf.org>
date Thu, 28 Jul 2016 10:55:44 -0700
parents 3bf799e80ca5
children 46d9b2972901
files @pyobject/dummy.m @pyobject/pyobject.m python_to_octave.cc
diffstat 3 files changed, 52 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/@pyobject/dummy.m	Fri Jul 29 20:15:39 2016 -0700
+++ b/@pyobject/dummy.m	Thu Jul 28 10:55:44 2016 -0700
@@ -25,8 +25,10 @@
 ## Simple example:
 ## @example
 ## @group
-## pyexec ("g = 6")
-## g = pyobject.fromPythonVarName ("g");
+## g = pyobject (int32 (6))
+##   @result{} g = [pyobject ...]
+##
+##       6
 ##
 ## sort (methods (g))
 ##   @result{} ans =
--- a/@pyobject/pyobject.m	Fri Jul 29 20:15:39 2016 -0700
+++ b/@pyobject/pyobject.m	Thu Jul 28 10:55:44 2016 -0700
@@ -52,16 +52,52 @@
         pyvarname, pyvarname);
       pyexec (cmd);
       id = pyeval (["hex(id(" pyvarname "))"]);
-      x = pyobject (id);
+      x = pyobject (0, id);
     endfunction
   endmethods
 
 
   methods
-    function x = pyobject (id)
-      % warning: not intended for casual use: you must also insert
-      % the object into the Python `__InOct__` dict with key `id`.
-      x.id = id;
+    function obj = pyobject (x, id)
+      if (nargin == 0)
+        obj = pyeval ("None");
+        return
+      endif
+
+      if (nargin == 1)
+        ## Convert the input to a pyobject
+        if (isa (x, "pyobject"))
+          obj = x;
+        else
+          ## XXX: perhaps not the ideal implementation!
+          vars = pyeval ("__import__('__main__').__dict__");
+          ## this is vars{"_temp"} = x
+          idx = struct ("type", "{}", "subs", {{"_temp"}});
+          vars = subsasgn (vars, idx, x);
+          cmd = [ ...
+            "if not ('__InOct__' in vars() or '__InOct__' in globals()):\n" ...
+            "    __InOct__ = dict()\n" ...
+            "    # FIXME: make it accessible elsewhere?\n" ...
+            "    import __main__\n" ...
+            "    __main__.__InOct__ = __InOct__\n" ...
+            "__InOct__[hex(id(_temp))] = _temp" ];
+          pyexec (cmd);
+          id = pyeval (["hex(id(_temp))"]);
+          obj = pyobject (0, id);
+        endif
+        return
+      endif
+
+      if (nargin == 2)
+        ## The actual constructor.  Nicer to split this off to static method
+        ## like `pyobject.new` but I don't know how to call from pycall.cc.
+        ## Warning: not intended for casual use: you must also insert the
+        ## object into the Python `__InOct__` dict with key `id`.
+        obj.id = id;
+        return
+      endif
+
+      error ("pyobject: unexpected input to the constructor")
     endfunction
 
     function delete (x)
@@ -154,3 +190,9 @@
 %!assert (char (pyeval ("[1, 2, 3, 4, 5]")), "[1, 2, 3, 4, 5]")
 %!assert (char (pyeval ("(1, 2, 3, 4, 5)")), "(1, 2, 3, 4, 5)")
 %!assert (char (pyeval ("__import__('sys')")), "<module 'sys' (built-in)>")
+
+%!assert (isa (pyobject (), "pyobject"))
+%!assert (isa (pyobject ("a string"), "pyobject"))
+%!assert (isa (pyobject (42.2), "pyobject"))
+%!assert (isa (pyobject (int32 (42)), "pyobject"))
+%!assert (isa (pyobject (pyobject ()), "pyobject"))
--- a/python_to_octave.cc	Fri Jul 29 20:15:39 2016 -0700
+++ b/python_to_octave.cc	Thu Jul 28 10:55:44 2016 -0700
@@ -500,7 +500,7 @@
           main_namespace, main_namespace);
     main_namespace["__InOct__"][id] = py_object;
     // Create @pyobject
-    oct_value = feval ("pyobject", ovl (id), 1);
+    oct_value = feval ("pyobject", ovl (0, id), 2);
   }
 
   void pyobj_to_octvalue (octave_value& oct_value,