# HG changeset patch # User Mike Miller # Date 1471290231 25200 # Node ID b8128a2e0e7014777dfc4cec13711952b9ee0b73 # Parent cee203ea62459ae62a052b1b50bceb9986ccad3a pyargs: New function to construct keyword arguments (see issue #45) * pyargs.m: New function to construct a type containing keyword arguments. diff -r cee203ea6245 -r b8128a2e0e70 pyargs.m --- /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 +## . + +## -*- 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")