changeset 332:b8128a2e0e70

pyargs: New function to construct keyword arguments (see issue #45) * pyargs.m: New function to construct a type containing keyword arguments.
author Mike Miller <mtmiller@octave.org>
date Mon, 15 Aug 2016 12:43:51 -0700
parents cee203ea6245
children 96b78e78a235
files pyargs.m
diffstat 1 files changed, 99 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyargs.m	Mon Aug 15 12:43:51 2016 -0700
@@ -0,0 +1,99 @@
+## Copyright (C) 2016 Mike Miller
+##
+## This file is part of Pytave.
+##
+## Pytave 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.
+##
+## Pytave 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 Pytave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} pyargs (@var{name}, @var{value})
+## @deftypefnx {} {} pyargs (@var{name}, @var{value}, @dots{})
+## Construct a set of Python keyword arguments suitable for passing to
+## a Python function.
+##
+## Python keyword arguments are similar to optional named parameters accepted
+## by some Octave functions such as @code{cellfun} or @code{set}.
+##
+## For example, a dictionary can be initialized with
+##
+## @example
+## @group
+## py.dict (pyargs ("one", 1, "two", 2))
+##       @result{} [pyobject ...]
+##           @{...@}
+## sort (cell (py.list (ans.keys ())))
+##       @result{}
+##           @{
+##             [1,1] = one
+##             [1,2] = two
+##           @}
+## @end group
+## @end example
+##
+## And a list can be sorted in reverse order with the @code{reverse} keyword
+##
+## @example
+## @group
+## x = py.list (num2cell (int32 ([1, 2, 3])));
+## x.sort (pyargs ("reverse", true));
+## x
+##       @result{} x = [pyobject ...]
+##           [3, 2, 1]
+## @end group
+## @end example
+## @end deftypefn
+
+function args = pyargs (varargin)
+
+  if (mod (nargin, 2) != 0)
+    error ("pyargs: must be called with NAME, VALUE pairs of arguments");
+  endif
+
+  keys_vals = {};
+  for i = 1:(nargin / 2)
+    k = varargin{2*i - 1};
+    v = varargin{2*i};
+    if (! (ischar (k) && isrow (k)))
+      error ("pyargs: NAME %d must be a string", i);
+    endif
+    try
+      v = pyobject (v);
+    catch
+      error ("pyargs: VALUE %d must be convertible to a Python object", i);
+    end_try_catch
+
+    keys_vals{i} = {k, v};
+  endfor
+
+  ## This function needs to return a Python mapping object that will be
+  ## recognized by other functions as containing keyword arguments.
+  ## Define the class using a type specifier so it can be defined and
+  ## instantiated as a single expression.
+  class_name = "_OctaveKwargs";
+  props = "{'is_kwargs_argument': False}";
+  args = pyeval (sprintf ("type('%s', (dict,), %s)()", class_name, props));
+  args.update (keys_vals);
+  args.is_kwargs_argument = true;
+
+endfunction
+
+
+%!assert (isa (pyargs (), "pyobject"))
+%!assert (sort (cell (py.list (py.dict (pyargs ()).keys ()))), cell (1, 0))
+%!xtest assert (sort (cell (py.list (py.dict (pyargs ("one", 1)).keys ()))), {"one"})
+%!assert (sort (cell (py.list (py.dict (pyargs ("one", 1, "two", 2)).keys ()))), {"one", "two"})
+
+%!error pyargs (1)
+%!error pyargs (1, 2)
+%!error pyargs ("one")