Mercurial > pytave
diff @pyobject/pyobject.m @ 209:57807b5fa7bf
Change name of pyobj to pyobject
author | genuinelucifer |
---|---|
date | Thu, 26 May 2016 11:35:20 -0700 |
parents | |
children | a54ab59c491d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/@pyobject/pyobject.m Thu May 26 11:35:20 2016 -0700 @@ -0,0 +1,135 @@ +%% 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 <http://www.gnu.org/licenses/>. + +%% -*- 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 + + end +end