# HG changeset patch # User Colin Macdonald # Date 1464329890 25200 # Node ID a54ab59c491ddf33b5e8b9e12f0b4d71c0f7ad5e # Parent 3edceb6b7504c9c7242d782c4fcf013747a0e971# Parent dbdf80450a1d10e6a1286f36d0d1e816c147ed0c merge genuinelucifer/cbm_pytave to macdonald/cbm_pytave diff -r 3edceb6b7504 -r a54ab59c491d @pyobj/dummy.m --- a/@pyobj/dummy.m Thu May 26 12:43:56 2016 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -%% Copyright (C) 2016 Colin B. Macdonald -%% -%% This file is part of PyTave. -%% -%% OctSymPy is free software; you can redistribute it and/or modify -%% it under the terms of the GNU General Public License as published -%% by the Free Software Foundation; either version 3 of the License, -%% or (at your option) any later version. -%% -%% This software is distributed in the hope that it will be useful, -%% but WITHOUT ANY WARRANTY; without even the implied warranty -%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -%% the GNU General Public License for more details. -%% -%% You should have received a copy of the GNU General Public -%% License along with this software; see the file COPYING. -%% If not, see . - -%% -*- texinfo -*- -%% @documentencoding UTF-8 -%% @defmethod @@pyobj dummy (@var{x}) -%% Does nothing, stores doctests for now. -%% -%% -%% Simple example: -%% @example -%% @group -%% pyexec('g = 6') -%% g = pyobj.fromPythonVarName('g'); -%% -%% sort(whatmethods(g)) -%% @result{} ans = -%% @{ -%% [1,1] = bit_length -%% [1,2] = conjugate -%% [1,1] = denominator -%% [1,2] = imag -%% [1,3] = numerator -%% [1,4] = real -%% @} -%% -%% g.numerator -%% @result{} ans = 6 -%% g.denominator -%% @result{} ans = 1 -%% @end group -%% @end example -%% -%% -%% You can delete an object in Python and it will persist: -%% @example -%% @group -%% pyexec('d = dict(one=1, two=2)') -%% x = pyobj.fromPythonVarName('d') -%% @result{} x = -%% [PyObject id ...] -%% @{'two': 2, 'one': 1@} -%% -%% % oops, overwrote d in Python: -%% pyexec('d = 42') -%% -%% % but have no fear, we still have a reference to it: -%% x -%% @result{} x = -%% [PyObject id ...] -%% @{'two': 2, 'one': 1@} -%% @end group -%% @end example -%% -%% We can accesss ``callables'' (methods) of objects: -%% @example -%% @group -%% x.keys() -%% @result{} ans = -%% @{ -%% [1,1] = two -%% [1,2] = one -%% @} -%% @end group -%% @end example -%% -%% @code{pyeval} returns a @@pyobj for things it cannot convert to -%% Octave-native objects: -%% @example -%% @group -%% pyexec('import sys') -%% sysmodule = pyeval('sys') -%% @result{} sysmodule = -%% [PyObject id ...] -%% -%% @end group -%% @end example -%% -%% After you have the object, you can access its properties: -%% @example -%% @group -%% sysmodule.version -%% @result{} ans = ... -%% @end group -%% @end example -%% -%% -%% TODO: this should return a cell array with a double, a string, -%% and an @@pyobj in it: -%% @example -%% @group -%% pyeval('[42, "hello", sys]') % doctest: +XFAIL -%% @result{} ans = -%% @{ -%% [1,1] = 42 -%% [1,2] = hello -%% [1,3] = -%% [PyObject id ...] -%% -%% @} -%% @end group -%% @end example -%% -%% @seealso{pyobj} -%% @end defmethod - -function dummy (x) - -end diff -r 3edceb6b7504 -r a54ab59c491d @pyobj/pyobj.m --- a/@pyobj/pyobj.m Thu May 26 12:43:56 2016 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -%% Copyright (C) 2016 Colin B. Macdonald -%% -%% This file is part of PyTave. -%% -%% OctSymPy is free software; you can redistribute it and/or modify -%% it under the terms of the GNU General Public License as published -%% by the Free Software Foundation; either version 3 of the License, -%% or (at your option) any later version. -%% -%% This software is distributed in the hope that it will be useful, -%% but WITHOUT ANY WARRANTY; without even the implied warranty -%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -%% the GNU General Public License for more details. -%% -%% You should have received a copy of the GNU General Public -%% License along with this software; see the file COPYING. -%% If not, see . - -%% -*- texinfo -*- -%% @documentencoding UTF-8 -%% @defun pyobj (@var{s}) -%% Wrap a Python object. -%% -%% TODO: where/how to document classdef classes? -%% -%% @seealso{pyexec, pyeval} -%% @end defun - -classdef pyobj < handle - properties - id - end - - methods(Static) - function x = fromPythonVarName(pyvarname) - % if @var{pyvarname} is a string, its assumed to be a variable - % name, e.g., previously created with pyexec. This must exist - % at the time of construction but it can disappear later (we - % will keep track of the reference). - if (~ ischar(pyvarname)) - error('pyobj: currently we only take variable names as input') - end - cmd = sprintf ([ ... - 'if not ("__InOct__" in vars() or "__InOct__" in globals()):\n' ... - ' __InOct__ = dict()\n' ... - '__InOct__[hex(id(%s))] = %s' ], ... - pyvarname, pyvarname); - pyexec (cmd); - id = pyeval (['hex(id(' pyvarname '))']); - x = pyobj(id); - end - end - - - methods - function x = pyobj(id) - % warning: not intended for casual use: you must also insert - % the object into the Python `__InOct__` dict with key `id`. - x.id = id; - end - - function delete(x) - % called on clear of the last reference---for subclasses of - % handle; not called at all for "value classes". - % FIXME: #46497 this is never called! - %save('proof_of_delete', 6, x.id) - disp ('delete') - % throws KeyError if it wasn't in there for some reason - cmd = sprintf ('__InOct__.pop("%s")', x.id); - pyexec (cmd); - end - - function force_delete (x) - % Manual workaround for #46497: call right before @code{clear x}. But - % be careful, @code{x} needs to be the last reference: don't do this: - % @example - % d = pyobj (...); - % d2 = d; - % force_delete (d) - % clear d - % d2 - % @print{} ... KeyError ... - % @end example - delete(x) - end - - dummy (x) - - function r = getid (x) - r = x.id; - end - - function disp(x) - printf ('[PyObject id %s]\n', x.id); - disp (pyeval (sprintf ('str(__InOct__["%s"])', x.id))) - end - - function s = whatclass(x) - s = pyeval (sprintf ('str(__InOct__["%s"].__class__)', x.id)); - end - - function lst = whatmethods(x) - % filter the output of `dir(x)` - % properties only: - % [a for a in dir(x) if not callable(getattr(x, a)) and not a.startswith("__")] - cmd = sprintf ( ... - '[a for a in dir(__InOct__["%s"]) if not a.startswith("__")]', ... - x.id); - lst = pyeval (cmd); - end - - function r = subsref(x, idx) - s = ''; - for i=1:length(idx) - t = idx(i); - switch t.type - case '()' - if ( ! isempty (t.subs)) - t - error('not implemented: function calls with arguments') - end - s = sprintf ('%s()', s); - case '.' - assert(ischar(t.subs)) - s = sprintf ('%s.%s', s, t.subs); - otherwise - t - error('not implemented') - end - end - r = pyeval (sprintf ('__InOct__["%s"]%s', x.id, s)); - end - - function vargout = help(x) - idx = struct('type', '.', 'subs', '__doc__'); - s = subsref(x, idx); - if (nargout == 0) - disp(s) - else - vargout = {s}; - end - end - - end -end diff -r 3edceb6b7504 -r a54ab59c491d @pyobject/dummy.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/@pyobject/dummy.m Thu May 26 23:18:10 2016 -0700 @@ -0,0 +1,124 @@ +%% Copyright (C) 2016 Colin B. Macdonald +%% +%% This file is part of PyTave. +%% +%% OctSymPy is free software; you can redistribute it and/or modify +%% it under the terms of the GNU General Public License as published +%% by the Free Software Foundation; either version 3 of the License, +%% or (at your option) any later version. +%% +%% This software is distributed in the hope that it will be useful, +%% but WITHOUT ANY WARRANTY; without even the implied warranty +%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +%% the GNU General Public License for more details. +%% +%% You should have received a copy of the GNU General Public +%% License along with this software; see the file COPYING. +%% If not, see . + +%% -*- texinfo -*- +%% @documentencoding UTF-8 +%% @defmethod @@pyobject dummy (@var{x}) +%% Does nothing, stores doctests for now. +%% +%% +%% Simple example: +%% @example +%% @group +%% pyexec('g = 6') +%% g = pyobject.fromPythonVarName('g'); +%% +%% sort(whatmethods(g)) +%% @result{} ans = +%% @{ +%% [1,1] = bit_length +%% [1,2] = conjugate +%% [1,1] = denominator +%% [1,2] = imag +%% [1,3] = numerator +%% [1,4] = real +%% @} +%% +%% g.numerator +%% @result{} ans = 6 +%% g.denominator +%% @result{} ans = 1 +%% @end group +%% @end example +%% +%% +%% You can delete an object in Python and it will persist: +%% @example +%% @group +%% pyexec('d = dict(one=1, two=2)') +%% x = pyobject.fromPythonVarName('d') +%% @result{} x = +%% [PyObject id ...] +%% @{'two': 2, 'one': 1@} +%% +%% % oops, overwrote d in Python: +%% pyexec('d = 42') +%% +%% % but have no fear, we still have a reference to it: +%% x +%% @result{} x = +%% [PyObject id ...] +%% @{'two': 2, 'one': 1@} +%% @end group +%% @end example +%% +%% We can accesss ``callables'' (methods) of objects: +%% @example +%% @group +%% x.keys() +%% @result{} ans = +%% @{ +%% [1,1] = two +%% [1,2] = one +%% @} +%% @end group +%% @end example +%% +%% @code{pyeval} returns a @@pyobject for things it cannot convert to +%% Octave-native objects: +%% @example +%% @group +%% pyexec('import sys') +%% sysmodule = pyeval('sys') +%% @result{} sysmodule = +%% [PyObject id ...] +%% +%% @end group +%% @end example +%% +%% After you have the object, you can access its properties: +%% @example +%% @group +%% sysmodule.version +%% @result{} ans = ... +%% @end group +%% @end example +%% +%% +%% TODO: this should return a cell array with a double, a string, +%% and an @@pyobject in it: +%% @example +%% @group +%% pyeval('[42, "hello", sys]') % doctest: +XFAIL +%% @result{} ans = +%% @{ +%% [1,1] = 42 +%% [1,2] = hello +%% [1,3] = +%% [PyObject id ...] +%% +%% @} +%% @end group +%% @end example +%% +%% @seealso{pyobject} +%% @end defmethod + +function dummy (x) + +end diff -r 3edceb6b7504 -r a54ab59c491d @pyobject/pyobject.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/@pyobject/pyobject.m Thu May 26 23:18:10 2016 -0700 @@ -0,0 +1,145 @@ +%% Copyright (C) 2016 Colin B. Macdonald +%% +%% This file is part of PyTave. +%% +%% OctSymPy is free software; you can redistribute it and/or modify +%% it under the terms of the GNU General Public License as published +%% by the Free Software Foundation; either version 3 of the License, +%% or (at your option) any later version. +%% +%% This software is distributed in the hope that it will be useful, +%% but WITHOUT ANY WARRANTY; without even the implied warranty +%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +%% the GNU General Public License for more details. +%% +%% You should have received a copy of the GNU General Public +%% License along with this software; see the file COPYING. +%% If not, see . + +%% -*- texinfo -*- +%% @documentencoding UTF-8 +%% @defun pyobject (@var{s}) +%% Wrap a Python object. +%% +%% TODO: where/how to document classdef classes? +%% +%% @seealso{pyexec, pyeval} +%% @end defun + +classdef pyobject < handle + properties + id + end + + methods(Static) + function x = fromPythonVarName(pyvarname) + % if @var{pyvarname} is a string, its assumed to be a variable + % name, e.g., previously created with pyexec. This must exist + % at the time of construction but it can disappear later (we + % will keep track of the reference). + if (~ ischar(pyvarname)) + error('pyobject: currently we only take variable names as input') + end + cmd = sprintf ([ ... + 'if not ("__InOct__" in vars() or "__InOct__" in globals()):\n' ... + ' __InOct__ = dict()\n' ... + '__InOct__[hex(id(%s))] = %s' ], ... + pyvarname, pyvarname); + pyexec (cmd); + id = pyeval (['hex(id(' pyvarname '))']); + x = pyobject(id); + end + end + + + 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; + end + + function delete(x) + % called on clear of the last reference---for subclasses of + % handle; not called at all for "value classes". + % FIXME: #46497 this is never called! + %save('proof_of_delete', 6, x.id) + disp ('delete') + % throws KeyError if it wasn't in there for some reason + cmd = sprintf ('__InOct__.pop("%s")', x.id); + pyexec (cmd); + end + + function force_delete (x) + % Manual workaround for #46497: call right before @code{clear x}. But + % be careful, @code{x} needs to be the last reference: don't do this: + % @example + % d = pyobject (...); + % d2 = d; + % force_delete (d) + % clear d + % d2 + % @print{} ... KeyError ... + % @end example + delete(x) + end + + dummy (x) + + function r = getid (x) + r = x.id; + end + + function disp(x) + printf ('[PyObject id %s]\n', x.id); + disp (pyeval (sprintf ('str(__InOct__["%s"])', x.id))) + end + + function s = whatclass(x) + s = pyeval (sprintf ('str(__InOct__["%s"].__class__)', x.id)); + end + + function lst = whatmethods(x) + % filter the output of `dir(x)` + % properties only: + % [a for a in dir(x) if not callable(getattr(x, a)) and not a.startswith("__")] + cmd = sprintf ( ... + '[a for a in dir(__InOct__["%s"]) if not a.startswith("__")]', ... + x.id); + lst = pyeval (cmd); + end + + function r = subsref(x, idx) + s = ''; + for i=1:length(idx) + t = idx(i); + switch t.type + case '()' + if ( ! isempty (t.subs)) + t + error('not implemented: function calls with arguments') + end + s = sprintf ('%s()', s); + case '.' + assert(ischar(t.subs)) + s = sprintf ('%s.%s', s, t.subs); + otherwise + t + error('not implemented') + end + end + r = pyeval (sprintf ('__InOct__["%s"]%s', x.id, s)); + end + + function vargout = help(x) + idx = struct('type', '.', 'subs', '__doc__'); + s = subsref(x, idx); + if (nargout == 0) + disp(s) + else + vargout = {s}; + end + end + + end +end diff -r 3edceb6b7504 -r a54ab59c491d Makefile.am diff -r 3edceb6b7504 -r a54ab59c491d pyeval.cc --- a/pyeval.cc Thu May 26 12:43:56 2016 -0700 +++ b/pyeval.cc Thu May 26 23:18:10 2016 -0700 @@ -90,14 +90,14 @@ } catch (pytave::object_convert_exception const &) { - printf ("pyeval: could not convert return value to Octave-native object, making pyobj...\n"); + printf ("pyeval: could not convert return value to Octave-native object, making pyobject...\n"); // Ensure we have a __InOct__ dict, and then put `res` into it exec ("if not (\"__InOct__\" in vars() or \"__InOct__\" in globals()):\n" " __InOct__ = dict()\n", main_namespace, main_namespace); main_namespace["__InOct__"][id] = res; - // Create @pyobj - retval = feval ("pyobj", ovl (id), 1); + // Create @pyobject + retval = feval ("pyobject", ovl (id), 1); } catch (error_already_set const &) { diff -r 3edceb6b7504 -r a54ab59c491d python_to_octave.cc