# HG changeset patch # User Mike Miller # Date 1472159216 25200 # Node ID 087e7bc3697fc1f084f098bcd4c2f651988b54e4 # Parent 1470ed26917afacd31582c1870d4bf44b8993f4d Do not automatically convert Python strings to Octave strings (fixes issue #65) * python_to_octave.cc (pytave::pyobj_to_octvalue): Drop conversion of bytes and unicode objects. * __py_struct_from_dict__.cc (F__py_string_value__): New function. * @pyobject/char.m: Define outside class definition, use __py_string_value__. * @pyobject/pyobject.m: Delete previous pyobject.char definition. * @pyobject/methods.m: Apply char conversion to __name__ attribute. * @py/py.m, @pyobject/cell.m, @pyobject/dummy.m, @pyobject/subsasgn.m, @pyobject/subsref.m, pyargs.m, pycall.cc, pyeval.cc: Adapt examples and tests to changes. diff -r 1470ed26917a -r 087e7bc3697f @py/py.m --- a/@py/py.m Thu Aug 25 12:11:02 2016 -0700 +++ b/@py/py.m Thu Aug 25 14:06:56 2016 -0700 @@ -27,7 +27,7 @@ endfunction %!assert (py.math.sqrt (2), sqrt (2)) -%!assert (ischar (py.sys.version)) +%!assert (ischar (char (py.sys.version))) %!test %! if (double (py.sys.hexversion) >= 0x03000000) diff -r 1470ed26917a -r 087e7bc3697f @pyobject/cell.m --- a/@pyobject/cell.m Thu Aug 25 12:11:02 2016 -0700 +++ b/@pyobject/cell.m Thu Aug 25 14:06:56 2016 -0700 @@ -42,7 +42,9 @@ ## @{ ## [1,1] = 10 ## [1,2] = 20 -## [1,3] = hello +## = [pyobject ...] +## +## hello ## @} ## @end group ## @end example @@ -84,7 +86,7 @@ %!assert (cell (pyeval ("[1.]")), {1}) %!assert (cell (pyeval ("[1., 2., 3.]")), {1, 2, 3}) %!assert (cell (pyeval ("(1., 2., 3.)")), {1, 2, 3}) -%!assert (cell (pyobject ("asdf")), {"a", "s", "d", "f"}) +%!assert (cellfun (@char, cell (pyobject ("asdf")), "uniformoutput", false), {"a", "s", "d", "f"}) %!test %! c = cell (pyeval ("range(10)")); diff -r 1470ed26917a -r 087e7bc3697f @pyobject/char.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/@pyobject/char.m Thu Aug 25 14:06:56 2016 -0700 @@ -0,0 +1,39 @@ +## 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 -*- +## @documentencoding UTF-8 +## @defmethod @@pyobject char (@var{x}) +## Conversion method to string. +## +## Example: +## @example +## @group +## s = pyobject ("hello world"); +## char (s) +## @result{} hello world +## @end group +## @end example +## @seealso{@@pyobject/disp} +## @end defmethod + +function s = char (x) + + s = __py_string_value__ (x); + +endfunction diff -r 1470ed26917a -r 087e7bc3697f @pyobject/dummy.m --- a/@pyobject/dummy.m Thu Aug 25 12:11:02 2016 -0700 +++ b/@pyobject/dummy.m Thu Aug 25 14:06:56 2016 -0700 @@ -140,7 +140,8 @@ ## @result{} ans = ## @{ ## [1,1] = 42 -## [1,2] = hello +## = [pyobject ...] +## hello ## = [pyobject ...] ## ## @} @@ -152,7 +153,7 @@ ## For example: ## @example ## @group -## pycall ("repr", sysmodule) +## char (pycall ("repr", sysmodule)) ## @result{} ## @end group ## @end example diff -r 1470ed26917a -r 087e7bc3697f @pyobject/methods.m --- a/@pyobject/methods.m Thu Aug 25 12:11:02 2016 -0700 +++ b/@pyobject/methods.m Thu Aug 25 14:06:56 2016 -0700 @@ -79,12 +79,12 @@ is_module = pyeval ("lambda x: isinstance(x, __import__('types').ModuleType)"); if (pycall (is_module, x)) - modulename = pycall ("getattr", x, "__name__"); + modulename = char (pycall ("getattr", x, "__name__")); printf ("Methods for Python module '%s':\n", modulename); else ## FIXME: should be `class (x)` classref = pycall ("getattr", x, "__class__"); - classname = pycall ("getattr", classref, "__name__"); + classname = char (pycall ("getattr", classref, "__name__")); printf ("Methods for Python class '%s':\n", classname); endif disp (list_in_columns (mtds_list)); diff -r 1470ed26917a -r 087e7bc3697f @pyobject/pyobject.m --- a/@pyobject/pyobject.m Thu Aug 25 12:11:02 2016 -0700 +++ b/@pyobject/pyobject.m Thu Aug 25 14:06:56 2016 -0700 @@ -77,6 +77,7 @@ endfunction # methods defined in external files + char (x) dummy (x) display (x) subsref (x, idx) @@ -85,10 +86,6 @@ r = x.m_id; endfunction - function s = char (x) - s = pycall ("str", x); - endfunction - function varargout = disp (x) s = char (x); if (nargout == 0) diff -r 1470ed26917a -r 087e7bc3697f @pyobject/subsasgn.m --- a/@pyobject/subsasgn.m Thu Aug 25 12:11:02 2016 -0700 +++ b/@pyobject/subsasgn.m Thu Aug 25 14:06:56 2016 -0700 @@ -92,7 +92,7 @@ %! L{2} = "Octave"; %! assert (length (L) == 2) %! assert (L{1}, 10) -%! assert (L{2}, "Octave") +%! assert (char (L{2}), "Octave") %!test %! % dict assignment, adding new keys diff -r 1470ed26917a -r 087e7bc3697f @pyobject/subsref.m --- a/@pyobject/subsref.m Thu Aug 25 12:11:02 2016 -0700 +++ b/@pyobject/subsref.m Thu Aug 25 14:06:56 2016 -0700 @@ -140,7 +140,7 @@ %! [a, b, c] = L{:}; %! assert (a, 1) %! assert (b, 2) -%! assert (c, "Octave") +%! assert (char (c), "Octave") %!test %! % 2D array indexing @@ -174,7 +174,7 @@ %!test %! % dict: floating point keys should work %! d = pyeval ("{5.5:'ok'}"); -%! assert (d{5.5}, "ok") +%! assert (char (d{5.5}), "ok") %!test %! % dict: make sure key ":" doesn't break anything @@ -209,7 +209,8 @@ %! pyexec ("import sys") %! s = pyeval ("set({sys})"); %! ver = s.pop ().version; -%! assert (ischar (ver)) +%! assert (isa (ver, "pyobject")) +%! assert (ischar (char (ver))) %!test %! % don't set "ans" if no return value diff -r 1470ed26917a -r 087e7bc3697f __py_struct_from_dict__.cc --- a/__py_struct_from_dict__.cc Thu Aug 25 12:11:02 2016 -0700 +++ b/__py_struct_from_dict__.cc Thu Aug 25 14:06:56 2016 -0700 @@ -211,6 +211,47 @@ return ovl (octave_uint64 (key)); } +DEFUN_DLD (__py_string_value__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {} {} __py_string_value__ (@var{obj})\n\ +Return the string value or representation of the Python object @var{obj}.\n\ +\n\ +This is a private internal function not intended for direct use.\n\ +@end deftypefn") +{ + if (args.length () != 1) + print_usage (); + + if (! (args(0).is_object () && args(0).class_name () == "pyobject")) + error ("pyobject.char: argument must be a valid Python object"); + + Py_Initialize (); + + PyObject *obj = pytave::pyobject_unwrap_object (args(0)); + if (! obj) + error ("pyobject.char: argument must be a valid Python object"); + + std::string str; + + if (PyBytes_Check (obj) || PyUnicode_Check (obj)) + str = pytave::extract_py_str (obj); + else if (Py_TYPE (obj)->tp_str != NULL) + { + PyObject *s = PyObject_Str (obj); + str = pytave::extract_py_str (s); + Py_DECREF (s); + } + else + { + Py_DECREF (obj); + error ("pyobject.char: cannot convert Python object to string"); + } + + Py_DECREF (obj); + + return ovl (str); +} + DEFUN_DLD (__py_struct_from_dict__, args, nargout, "-*- texinfo -*-\n\ @deftypefn {} {} __py_struct_from_dict__ (@var{dict})\n\ diff -r 1470ed26917a -r 087e7bc3697f pyargs.m --- a/pyargs.m Thu Aug 25 12:11:02 2016 -0700 +++ b/pyargs.m Thu Aug 25 14:06:56 2016 -0700 @@ -32,7 +32,7 @@ ## py.dict (pyargs ("one", 1, "two", 2)) ## @result{} [pyobject ...] ## @{...@} -## sort (cell (py.list (ans.keys ()))) +## sort (cellfun (@@char, cell (py.list (ans.keys ())), "uniformoutput", false)) ## @result{} ## @{ ## [1,1] = one @@ -90,9 +90,9 @@ %!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"}) +%!assert (cell (py.list (py.dict (pyargs ()).keys ())), cell (1, 0)) +%!assert (sort (cellfun (@char, cell (py.list (py.dict (pyargs ("one", 1)).keys ())), "uniformoutput", false)), {"one"}) +%!assert (sort (cellfun (@char, cell (py.list (py.dict (pyargs ("one", 1, "two", 2)).keys ())), "uniformoutput", false)), {"one", "two"}) %!error pyargs (1) %!error pyargs (1, 2) diff -r 1470ed26917a -r 087e7bc3697f pycall.cc --- a/pycall.cc Thu Aug 25 12:11:02 2016 -0700 +++ b/pycall.cc Thu Aug 25 14:06:56 2016 -0700 @@ -147,13 +147,13 @@ } /* -%!assert (ischar (pycall ("os.getcwd"))) %!assert (isreal (pycall ("random.random"))) %!assert (double (pycall ("math.exp", 3)), exp (3)) %!assert (double (pycall ("math.trunc", pi)), fix (pi)) %!assert (double (pycall ("math.sqrt", 2)), sqrt (2)) %!assert (double (pycall ("cmath.sqrt", 2j)), sqrt (2j)) %!assert (double (pycall ("int", 10.2)), 10) +%!assert (isa (pycall ("os.getcwd"), "pyobject")) %!assert (isa (pycall ("object"), "pyobject")) %!assert (isa (pycall ("dict"), "pyobject")) %!assert (isa (pycall ("list"), "pyobject")) @@ -166,14 +166,14 @@ %! " if s == 'long':\n" ... %! " return 'int'\n" ... %! " return s"]); -%!assert (pycall ("typename", 0), "float") -%!assert (pycall ("typename", pi), "float") -%!assert (pycall ("typename", 2j), "complex") -%!assert (pycall ("typename", int32 (0)), "int") -%!assert (pycall ("typename", false), "bool") -%!assert (pycall ("typename", true), "bool") -%!assert (pycall ("typename", "Hello world"), "str") -%!assert (pycall ("typename", char ([1, 2, 3])), "str") +%!assert (char (pycall ("typename", 0)), "float") +%!assert (char (pycall ("typename", pi)), "float") +%!assert (char (pycall ("typename", 2j)), "complex") +%!assert (char (pycall ("typename", int32 (0))), "int") +%!assert (char (pycall ("typename", false)), "bool") +%!assert (char (pycall ("typename", true)), "bool") +%!assert (char (pycall ("typename", "Hello world")), "str") +%!assert (char (pycall ("typename", char ([1, 2, 3]))), "str") ## Test construction of sequence types from cell arrays %!assert (char (pycall ("list")), "[]") @@ -190,7 +190,7 @@ ## Test construction of dict from pyargs %!test %! a = pycall ("dict", pyargs ("a", 1, "b", 2, "c", 3)); -%! assert (sort (cell (pycall ("list", a.keys ()))), {"a", "b", "c"}) +%! assert (sort (cellfun (@char, cell (pycall ("list", a.keys ())), "uniformoutput", false)), {"a", "b", "c"}) %! assert (sort (double (pycall ("array.array", "d", a.values ()))), [1, 2, 3]) ## Test copy construction of dict from dict @@ -208,7 +208,7 @@ ## Test round trip type preservation / conversion %!test %! pyexec ("def roundtrip(x): return x"); -%! values = { 0, pi, 2j, eps, false, true, version, "Hello world" }; +%! values = { 0, pi, 2j, eps, false, true }; %! for i = 1:numel (values) %! assert (pycall ("roundtrip", values{i}), values{i}); %! endfor diff -r 1470ed26917a -r 087e7bc3697f pyeval.cc --- a/pyeval.cc Thu Aug 25 12:11:02 2016 -0700 +++ b/pyeval.cc Thu Aug 25 14:06:56 2016 -0700 @@ -125,8 +125,8 @@ %!assert (iscomplex (pyeval ("2j"))) %!assert (pyeval ("2j"), 2j) -%!assert (ischar (pyeval ("\"I <3 Octave\""))) -%!assert (pyeval ("\"I <3 Octave\""), "I <3 Octave") +%!assert (ischar (char (pyeval ("\"I <3 Octave\"")))) +%!assert (char (pyeval ("\"I <3 Octave\"")), "I <3 Octave") %!assert (islogical (pyeval ("True"))) %!assert (islogical (pyeval ("False"))) diff -r 1470ed26917a -r 087e7bc3697f python_to_octave.cc --- a/python_to_octave.cc Thu Aug 25 12:11:02 2016 -0700 +++ b/python_to_octave.cc Thu Aug 25 14:06:56 2016 -0700 @@ -327,8 +327,6 @@ oct_value = extract_py_complex (py_object.ptr ()); else if (arrayx.check ()) pyarr_to_octvalue (oct_value, (PyArrayObject*)py_object.ptr ()); - else if (PyBytes_Check (py_object.ptr ()) || PyUnicode_Check (py_object.ptr ())) - oct_value = extract_py_str (py_object.ptr ()); else oct_value = pyobject_wrap_object (py_object.ptr ()); }