# HG changeset patch # User Colin Macdonald # Date 1466226928 25200 # Node ID 7feece80fbfa61d4f3e9d6ab1607bed876822054 # Parent 06835a3e33848bd1c6fe2663bdc3909f47fc1a09 pyobject: Octave-style formatting, minor edits * @pyobject/pyobject.m: reformat, add test * @pyobject/dummy.m: reformat, xfail a test * @pyobject/display.m: reformat diff -r 06835a3e3384 -r 7feece80fbfa @pyobject/display.m --- a/@pyobject/display.m Fri Jun 17 22:13:54 2016 -0700 +++ b/@pyobject/display.m Fri Jun 17 22:15:28 2016 -0700 @@ -1,62 +1,61 @@ -%% 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 . +## 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 display (@var{x}) -%% Custom display for pyobjects. -%% -%% Example: -%% @example -%% @group -%% pyexec('import sys') -%% sysmodule = pyeval('sys') -%% @result{} sysmodule = [pyobject ...] -%% -%% -%% -%% @end group -%% @end example -%% -%% @seealso{@@pyobject/disp} -%% @end defmethod +## -*- texinfo -*- +## @documentencoding UTF-8 +## @defmethod @@pyobject display (@var{x}) +## Custom display for pyobjects. +## +## Example: +## @example +## @group +## pyexec('import sys') +## sysmodule = pyeval('sys') +## @result{} sysmodule = [pyobject ...] +## +## +## +## @end group +## @end example +## +## @seealso{@@pyobject/disp} +## @end defmethod function display (x) - loose = eval('! __compactformat__ ()'); + loose = ! __compactformat__ (); - printf ('%s = [pyobject %s]\n', inputname (1), getid (x)); + printf ("%s = [pyobject %s]\n", inputname (1), getid (x)); s = disp (x); s = make_indented (s); - if (loose), printf('\n'); end - disp(s) - if (loose), printf('\n'); end + if (loose), printf("\n"); endif + disp (s) + if (loose), printf("\n"); endif -end +endfunction function s = make_indented(s, n) if (nargin == 1) n = 2; - end - pad = char (double (' ')*ones (1,n)); - newl = sprintf('\n'); - s = strrep (s, newl, [newl pad]); - s = [pad s]; % first line -end + endif + pad = char (double (" ")*ones (1,n)); + s = strrep (s, "\n", ["\n" pad]); + s = [pad s]; # first line +endfunction diff -r 06835a3e3384 -r 7feece80fbfa @pyobject/dummy.m --- a/@pyobject/dummy.m Fri Jun 17 22:13:54 2016 -0700 +++ b/@pyobject/dummy.m Fri Jun 17 22:15:28 2016 -0700 @@ -1,130 +1,131 @@ -%% 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 . +## 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,3] = denominator -%% [1,4] = imag -%% [1,5] = numerator -%% [1,6] = 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 ...] -%% @{'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 ...] -%% @{'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 ...] -%% -%% @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 -%% -%% A @@pyobject can be passed back to Python. This does not make -%% a copy but rather a reference to the original object. -%% For example: -%% @example -%% @group -%% pycall('__builtin__.print', sysmodule) -%% @print{} -%% @end group -%% @end example -%% -%% @seealso{pyobject} -%% @end defmethod +## -*- 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 (methods (g)) +## @result{} ans = +## @{ +## [1,1] = bit_length +## [1,2] = conjugate +## [1,3] = denominator +## [1,4] = imag +## [1,5] = numerator +## [1,6] = 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 ...] +## @{'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 ...] +## @{'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 ...] +## +## @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 +## +## A @@pyobject can be passed back to Python. This does not make +## a copy but rather a reference to the original object. +## For example: +## @example +## @group +## pycall ("__builtin__.print", sysmodule) # doctest: +XFAIL +## @print{} +## @end group +## @end example +## (FIXME: I think this failure may correspond to an existing doctest issue). +## +## @seealso{pyobject} +## @end defmethod function dummy (x) diff -r 06835a3e3384 -r 7feece80fbfa @pyobject/pyobject.m --- a/@pyobject/pyobject.m Fri Jun 17 22:13:54 2016 -0700 +++ b/@pyobject/pyobject.m Fri Jun 17 22:15:28 2016 -0700 @@ -1,30 +1,31 @@ -%% 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 . +## 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 +## -*- 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 @@ -33,13 +34,14 @@ 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 + # Warning: just for testing, may be removed without notice! + # 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") + endif cmd = sprintf ([ ... 'if not ("__InOct__" in vars() or "__InOct__" in globals()):\n' ... ' __InOct__ = dict()\n' ... @@ -49,10 +51,10 @@ '__InOct__[hex(id(%s))] = %s' ], ... pyvarname, pyvarname); pyexec (cmd); - id = pyeval (['hex(id(' pyvarname '))']); + id = pyeval (["hex(id(" pyvarname "))"]); x = pyobject (id); - end - end + endfunction + endmethods methods @@ -60,7 +62,7 @@ % warning: not intended for casual use: you must also insert % the object into the Python `__InOct__` dict with key `id`. x.id = id; - end + endfunction function delete (x) # Called on clear of the last reference---for subclasses of @@ -83,38 +85,44 @@ # throws KeyError if it wasn't in there for some reason cmd = sprintf ("__InOct__.pop('%s')", x.id); pyexec (cmd) - end + endfunction + # methods defined in external files dummy (x) display (x) subsref (x, idx) function r = getid (x) r = x.id; - end + endfunction function varargout = disp (x) - s = pyeval (sprintf ('str(__InOct__["%s"])', x.id)); + s = pyeval (sprintf ("str(__InOct__['%s'])", x.id)); if (nargout == 0) disp (s) else varargout = {s}; - end - end + endif + endfunction function s = whatclass (x) - s = pyeval (sprintf ('str(__InOct__["%s"].__class__)', x.id)); - end + s = pyeval (sprintf ("str(__InOct__['%s'].__class__)", x.id)); + endfunction function vargout = help (x) - idx = struct ('type', '.', 'subs', '__doc__'); + idx = struct ("type", ".", "subs", "__doc__"); s = subsref (x, idx); if (nargout == 0) disp (s) else vargout = {s}; - end - end + endif + endfunction + endmethods +endclassdef - end -end + +%!test +%! pyexec ("import sys") +%! A = pyeval ("sys"); +%! assert (isa (A, "pyobject"))