# HG changeset patch # User Mike Miller # Date 1493943218 25200 # Node ID 8247f298fd16fa0ab5589fa2185802427a4d1a7a # Parent 24555fba9964571b305884e1782fbc53ef76edc1 Raise Octave errors instead of exceptions for conversion errors * Makefile.am (COMMON_SOURCE_FILES): Include oct-py-error.cc in the list. (PYTAVE_HEADER_FILES): Include oct-py-error.h in the list. * oct-py-error.cc, oct-py-error.h: New files defining error conditions. * oct-py-types.cc (pytave::extract_py_bool, pytave::extract_py_complex, pytave::extract_py_float, pytave::make_py_array, pytave::extract_py_scalar_map, pytave::extract_py_int64, pytave::extract_py_uint64, pytave::extract_py_str): Use new error condition functions instead of throwing exceptions. (pytave::make_py_array, pytave::make_py_numeric_value, pytave::make_py_tuple): Raise Octave error instead of throwing exceptions. * __py_struct_from_dict__.cc (F__py_int64_scalar_value__, F__py_uint64_scalar_value__): Remove exception handling logic. * pycall.cc (Fpycall): Remove conversion exception handlers. * pyeval.cc (Fpyeval): Likewise. * pyexec.cc (Fpyexec): Likewise. * exceptions.h (pytave::pytave_exception, pytave::octave_error_exception, pytave::octave_parse_exception, pytave::value_convert_exception, pytave::object_convert_exception, pytave::variable_name_exception): Delete no longer used exception types. diff -r 24555fba9964 -r 8247f298fd16 Makefile.am --- a/Makefile.am Thu May 04 13:22:20 2017 -0700 +++ b/Makefile.am Thu May 04 17:13:38 2017 -0700 @@ -30,6 +30,7 @@ COMMON_SOURCE_FILES = \ exceptions.cc \ + oct-py-error.cc \ oct-py-eval.cc \ oct-py-init.cc \ oct-py-types.cc \ @@ -66,6 +67,7 @@ PYTAVE_HEADER_FILES = \ config.h \ exceptions.h \ + oct-py-error.h \ oct-py-eval.h \ oct-py-init.h \ oct-py-object.h \ diff -r 24555fba9964 -r 8247f298fd16 __py_struct_from_dict__.cc --- a/__py_struct_from_dict__.cc Thu May 04 13:22:20 2017 -0700 +++ b/__py_struct_from_dict__.cc Thu May 04 17:13:38 2017 -0700 @@ -27,7 +27,6 @@ #include #include -#include "exceptions.h" #include "oct-py-init.h" #include "oct-py-object.h" #include "oct-py-types.h" @@ -88,24 +87,7 @@ pytave::py_init (); pytave::python_object obj = pytave::pyobject_unwrap_object (args(0)); - if (! obj) - error ("pyobject.int64: argument must be a valid Python object"); - - octave_int64 retval; - - try - { - retval = pytave::extract_py_int64 (obj); - } - catch (pytave::object_convert_exception const &) - { - error ("pyobject.int64: argument must be a Python int or long object"); - } - catch (pytave::error_already_set const &) - { - std::string message = pytave::fetch_exception_message (); - error ("pyobject.int64: %s", message.c_str ()); - } + octave_int64 retval = pytave::extract_py_int64 (obj); return ovl (retval); } @@ -140,24 +122,7 @@ pytave::py_init (); pytave::python_object obj = pytave::pyobject_unwrap_object (args(0)); - if (! obj) - error ("pyobject.uint64: argument must be a valid Python object"); - - octave_uint64 retval; - - try - { - retval = pytave::extract_py_uint64 (obj); - } - catch (pytave::object_convert_exception const &) - { - error ("pyobject.uint64: argument must be a Python int or long object"); - } - catch (pytave::error_already_set const &) - { - std::string message = pytave::fetch_exception_message (); - error ("pyobject.uint64: %s", message.c_str ()); - } + octave_uint64 retval = pytave::extract_py_uint64 (obj); return ovl (retval); } diff -r 24555fba9964 -r 8247f298fd16 exceptions.h --- a/exceptions.h Thu May 04 13:22:20 2017 -0700 +++ b/exceptions.h Thu May 04 17:13:38 2017 -0700 @@ -29,60 +29,6 @@ namespace pytave { - class pytave_exception - { - public: - pytave_exception (const std::string& err) { error = err; }; - - private: - std::string error; - }; - - class octave_error_exception - { - public: - octave_error_exception (const std::string& err) { error = err; }; - - private: - std::string error; - }; - - class octave_parse_exception - { - public: - octave_parse_exception (const std::string& err) { error = err; }; - - private: - std::string error; - }; - - class value_convert_exception - { - public: - value_convert_exception (const std::string& err) { error = err; }; - - private: - std::string error; - }; - - class object_convert_exception - { - public: - object_convert_exception (const std::string& err) { error = err; }; - - private: - std::string error; - }; - - class variable_name_exception - { - public: - variable_name_exception (const std::string& err) { error = err; }; - - private: - std::string error; - }; - class error_already_set { }; diff -r 24555fba9964 -r 8247f298fd16 oct-py-error.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oct-py-error.cc Thu May 04 17:13:38 2017 -0700 @@ -0,0 +1,48 @@ +/* + +Copyright (C) 2017 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 +. + +*/ + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include + +#include "oct-py-error.h" + +namespace pytave +{ + + void + error_conversion_invalid_python_object (const std::string& to) + { + error ("unable to convert to %s, invalid Python object", to.c_str ()); + } + + void + error_conversion_mismatch_python_type (const std::string& to, + const std::string& must) + { + error ("unable to convert to %s, must be a Python %s", to.c_str (), + must.c_str ()); + } + +} diff -r 24555fba9964 -r 8247f298fd16 oct-py-error.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oct-py-error.h Thu May 04 17:13:38 2017 -0700 @@ -0,0 +1,50 @@ +/* + +Copyright (C) 2017 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 +. + +*/ + +#if ! defined (pytave_oct_py_error_h) +#define pytave_oct_py_error_h 1 + +#include + +#if defined (__GNUC__) +# define PYTAVE_ATTR_NORETURN __attribute__((__noreturn__)) +#else +# define PYTAVE_ATTR_NORETURN +#endif + +namespace pytave +{ + + void + error_conversion_invalid_python_object (const std::string& to) + PYTAVE_ATTR_NORETURN; + + void + error_conversion_mismatch_python_type (const std::string& to, + const std::string& must) + PYTAVE_ATTR_NORETURN; + +} + +#undef PYTAVE_ATTR_NORETURN + +#endif diff -r 24555fba9964 -r 8247f298fd16 oct-py-types.cc --- a/oct-py-types.cc Thu May 04 13:22:20 2017 -0700 +++ b/oct-py-types.cc Thu May 04 17:13:38 2017 -0700 @@ -32,6 +32,7 @@ #include #include "exceptions.h" +#include "oct-py-error.h" #include "oct-py-eval.h" #include "oct-py-object.h" #include "oct-py-types.h" @@ -65,10 +66,10 @@ extract_py_bool (PyObject *obj) { if (! obj) - throw object_convert_exception ("failed to extract boolean: null object"); + error_conversion_invalid_python_object ("a boolean value"); if (! PyBool_Check (obj)) - throw object_convert_exception ("failed to extract boolean: wrong type"); + error_conversion_mismatch_python_type ("a boolean value", "bool"); return (obj == Py_True); } @@ -77,10 +78,10 @@ extract_py_complex (PyObject *obj) { if (! obj) - throw object_convert_exception ("failed to extract complex: null object"); + error_conversion_invalid_python_object ("a complex value"); if (! PyComplex_Check (obj)) - throw object_convert_exception ("failed to extract complex: wrong type"); + error_conversion_mismatch_python_type ("a complex value", "complex"); Py_complex value = PyComplex_AsCComplex (obj); return std::complex {value.real, value.imag}; @@ -90,10 +91,10 @@ extract_py_float (PyObject *obj) { if (! obj) - throw object_convert_exception ("failed to extract float: null object"); + error_conversion_invalid_python_object ("a floating point value"); if (! PyFloat_Check (obj)) - throw object_convert_exception ("failed to extract float: wrong type"); + error_conversion_mismatch_python_type ("a floating point value", "float"); return PyFloat_AsDouble (obj); } @@ -138,8 +139,7 @@ make_py_array (const void *data, size_t len, char typecode) { if (! typecode) - throw object_convert_exception - ("unable to create array from Octave data"); + error ("unable to create array, invalid array type code"); std::string arg { typecode }; python_object array = py_call_function ("array.array", ovl (arg)); @@ -242,81 +242,88 @@ PyObject * make_py_numeric_value (const octave_value& value) { - if (value.is_scalar_type ()) - { - if (value.is_bool_type ()) - return make_py_bool (value.bool_value ()); + if (! value.is_scalar_type ()) + error ("unable to convert non-scalar type \"%s\" to a Python number", + value.type_name ().c_str ()); + + if (value.is_bool_type ()) + return make_py_bool (value.bool_value ()); - else if (value.is_int8_type ()) - return make_py_int (value.int8_scalar_value ().value ()); - else if (value.is_int16_type ()) - return make_py_int (value.int16_scalar_value ().value ()); - else if (value.is_int32_type ()) - return make_py_int (value.int32_scalar_value ().value ()); - else if (value.is_int64_type ()) - return make_py_int (value.int64_scalar_value ().value ()); + else if (value.is_int8_type ()) + return make_py_int (value.int8_scalar_value ().value ()); + else if (value.is_int16_type ()) + return make_py_int (value.int16_scalar_value ().value ()); + else if (value.is_int32_type ()) + return make_py_int (value.int32_scalar_value ().value ()); + else if (value.is_int64_type ()) + return make_py_int (value.int64_scalar_value ().value ()); - else if (value.is_uint8_type ()) - return make_py_int (value.uint8_scalar_value ().value ()); - else if (value.is_uint16_type ()) - return make_py_int (value.uint16_scalar_value ().value ()); - else if (value.is_uint32_type ()) - return make_py_int (value.uint32_scalar_value ().value ()); - else if (value.is_uint64_type ()) - return make_py_int (value.uint64_scalar_value ().value ()); + else if (value.is_uint8_type ()) + return make_py_int (value.uint8_scalar_value ().value ()); + else if (value.is_uint16_type ()) + return make_py_int (value.uint16_scalar_value ().value ()); + else if (value.is_uint32_type ()) + return make_py_int (value.uint32_scalar_value ().value ()); + else if (value.is_uint64_type ()) + return make_py_int (value.uint64_scalar_value ().value ()); - else if (value.is_complex_type ()) - return make_py_complex (value.complex_value ()); - else if (value.is_float_type ()) - return make_py_float (value.double_value ()); - } + else if (value.is_complex_type ()) + return make_py_complex (value.complex_value ()); + else if (value.is_float_type ()) + return make_py_float (value.double_value ()); + else + error ("unable to convert unhandled scalar type \"%s\" to a " + "Python number", value.type_name ().c_str ()); - throw value_convert_exception ("unhandled scalar type"); - return 0; + return nullptr; } PyObject * make_py_array (const octave_value& value) { - if (value.is_numeric_type () && ! value.is_complex_type () - && value.ndims () == 2 && (value.columns () <= 1 || value.rows () <= 1)) - { - if (value.is_double_type ()) - return make_py_array (value.array_value ()); - else if (value.is_single_type ()) - return make_py_array (value.float_array_value ()); + if (! (value.is_numeric_type () && ! value.is_complex_type () + && value.ndims () == 2 + && (value.columns () <= 1 || value.rows () <= 1))) + error ("unable to convert non-vector type \"%s\" to a Python array", + value.type_name ().c_str ()); + + if (value.is_double_type ()) + return make_py_array (value.array_value ()); + else if (value.is_single_type ()) + return make_py_array (value.float_array_value ()); - else if (value.is_int8_type ()) - return make_py_array (value.int8_array_value ()); - else if (value.is_int16_type ()) - return make_py_array (value.int16_array_value ()); - else if (value.is_int32_type ()) - return make_py_array (value.int32_array_value ()); - else if (value.is_int64_type ()) - return make_py_array (value.int64_array_value ()); + else if (value.is_int8_type ()) + return make_py_array (value.int8_array_value ()); + else if (value.is_int16_type ()) + return make_py_array (value.int16_array_value ()); + else if (value.is_int32_type ()) + return make_py_array (value.int32_array_value ()); + else if (value.is_int64_type ()) + return make_py_array (value.int64_array_value ()); - else if (value.is_uint8_type ()) - return make_py_array (value.uint8_array_value ()); - else if (value.is_uint16_type ()) - return make_py_array (value.uint16_array_value ()); - else if (value.is_uint32_type ()) - return make_py_array (value.uint32_array_value ()); - else if (value.is_uint64_type ()) - return make_py_array (value.uint64_array_value ()); - } + else if (value.is_uint8_type ()) + return make_py_array (value.uint8_array_value ()); + else if (value.is_uint16_type ()) + return make_py_array (value.uint16_array_value ()); + else if (value.is_uint32_type ()) + return make_py_array (value.uint32_array_value ()); + else if (value.is_uint64_type ()) + return make_py_array (value.uint64_array_value ()); + else + error ("unable to convert unhandled vector type \"%s\" to a " + "Python array", value.type_name ().c_str ()); - throw value_convert_exception ("unhandled Octave numeric vector type"); - return 0; + return nullptr; } octave_scalar_map extract_py_scalar_map (PyObject *obj) { if (! obj) - error ("unable to convert to an Octave struct, invalid Python object"); + error_conversion_invalid_python_object ("an Octave struct"); if (! PyDict_Check (obj)) - error ("unable to convert to an Octave struct, must be a Python dict"); + error_conversion_mismatch_python_type ("an Octave struct", "dict"); octave_scalar_map map; @@ -364,7 +371,7 @@ extract_py_int64 (PyObject *obj) { if (! obj) - throw object_convert_exception ("failed to extract integer: null object"); + error_conversion_invalid_python_object ("a signed integer value"); if (PyLong_Check (obj)) { @@ -388,7 +395,8 @@ return PyInt_AsLong (obj); #endif else - throw object_convert_exception ("failed to extract integer: wrong type"); + error_conversion_mismatch_python_type ("a signed integer value", + "int or long"); return 0; } @@ -397,7 +405,7 @@ extract_py_uint64 (PyObject *obj) { if (! obj) - throw object_convert_exception ("failed to extract integer: null object"); + error_conversion_invalid_python_object ("an unsigned integer value"); if (PyLong_Check (obj)) { @@ -425,7 +433,8 @@ return static_cast (PyInt_AsLong (obj)); #endif else - throw object_convert_exception ("failed to extract integer: wrong type"); + error_conversion_mismatch_python_type ("an unsigned integer value", + "int or long"); return 0; } @@ -434,8 +443,7 @@ make_py_tuple (const Cell& cell) { if (! (cell.is_empty () || cell.is_vector ())) - throw value_convert_exception ( - "unable to convert multidimensional cell array into Python tuple"); + error ("unable to convert multidimensional cell array to a Python tuple"); octave_idx_type size = cell.numel (); PyObject *tuple = PyTuple_New (size); @@ -457,7 +465,8 @@ std::string retval; if (! obj) - throw object_convert_exception ("failed to extract string: null object"); + error_conversion_invalid_python_object ("a string value"); + if (PyBytes_Check (obj)) { retval.assign (PyBytes_AsString (obj), PyBytes_Size (obj)); @@ -468,11 +477,10 @@ if (enc && PyBytes_Check (enc)) retval.assign (PyBytes_AsString (enc), PyBytes_Size (enc)); else - throw object_convert_exception - ("failed to extract string: UTF-8 error"); + octave_throw_bad_alloc (); } else - throw object_convert_exception ("failed to extract string: wrong type"); + error_conversion_mismatch_python_type ("a string value", "str"); return retval; } diff -r 24555fba9964 -r 8247f298fd16 pycall.cc --- a/pycall.cc Thu May 04 13:22:20 2017 -0700 +++ b/pycall.cc Thu May 04 17:13:38 2017 -0700 @@ -113,14 +113,6 @@ if (nargout > 0 || ! res.is_none ()) retval(0) = pytave::py_implicitly_convert_return_value (res); } - catch (pytave::object_convert_exception const &) - { - error ("pyexec: error in return value type conversion"); - } - catch (pytave::value_convert_exception const &) - { - error ("pycall: error in argument type conversion"); - } catch (pytave::error_already_set const &) { std::string message = pytave::fetch_exception_message (); diff -r 24555fba9964 -r 8247f298fd16 pyeval.cc --- a/pyeval.cc Thu May 04 13:22:20 2017 -0700 +++ b/pyeval.cc Thu May 04 17:13:38 2017 -0700 @@ -88,10 +88,6 @@ if (nargout > 0 || ! res.is_none ()) retval(0) = pytave::py_implicitly_convert_return_value (res); } - catch (pytave::object_convert_exception const &) - { - error ("pyexec: error in return value type conversion"); - } catch (pytave::error_already_set const &) { std::string message = pytave::fetch_exception_message (); diff -r 24555fba9964 -r 8247f298fd16 pyexec.cc --- a/pyexec.cc Thu May 04 13:22:20 2017 -0700 +++ b/pyexec.cc Thu May 04 17:13:38 2017 -0700 @@ -79,10 +79,6 @@ // FIXME: figure out exec return code: pytave::py_exec_string (code, 0, local_namespace); } - catch (pytave::object_convert_exception const &) - { - error ("pyexec: error in return value type conversion"); - } catch (pytave::error_already_set const &) { std::string message = pytave::fetch_exception_message ();