changeset 231:6fffa6219b2c

Properly extract exception text from Python (fixes issue #24) * exceptions.{h, cc}: Add a new method to properly extract string for a python exception. Also add a new error message if we can't extract the error string. * pycall.cc, pyeval.cc, pyexec.cc: Use the new method to extract string when an exception occurs.
author Abhinav Tripathi <genuinelucifer@gmail.com>
date Sat, 16 Jul 2016 05:50:36 -0700
parents 377f2dc057ea
children c02f0a4c92e7
files exceptions.cc exceptions.h pycall.cc pyeval.cc pyexec.cc
diffstat 5 files changed, 50 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/exceptions.cc	Fri Jul 15 00:51:23 2016 -0700
+++ b/exceptions.cc	Sat Jul 16 05:50:36 2016 -0700
@@ -45,4 +45,30 @@
             && octave_parse_exception::init ()
             && variable_name_exception::init ());
   }
+
+  std::string fetch_exception_message (void)
+  {
+    using namespace boost::python;
+    PyObject *ptype, *pvalue, *ptraceback;
+    PyErr_Fetch (&ptype, &pvalue, &ptraceback);
+    std::string message;
+
+    try
+      {
+        object formatted_list, formatted;
+        handle<> htype (ptype), hval (allow_null (pvalue));
+        object traceback (import ("traceback"));
+        object format_exception_only (traceback.attr ("format_exception_only"));
+        formatted_list = format_exception_only (htype, hval);
+        formatted = str ("\n").join (formatted_list);
+        message = extract<std::string> (formatted);
+      }
+    catch (error_already_set const &)
+      {
+        PyErr_Restore (ptype, pvalue, ptraceback);
+        PyErr_Print ();
+        message = std::string ("Something weird happened. See traceback above ^");
+      }
+    return message;
+  }
 }
--- a/exceptions.h	Fri Jul 15 00:51:23 2016 -0700
+++ b/exceptions.h	Sat Jul 16 05:50:36 2016 -0700
@@ -159,6 +159,7 @@
   };
 
   bool init_exceptions (void);
+  std::string fetch_exception_message (void);
 }
 
 #endif
--- a/pycall.cc	Fri Jul 15 00:51:23 2016 -0700
+++ b/pycall.cc	Sat Jul 16 05:50:36 2016 -0700
@@ -182,19 +182,8 @@
     }
   catch (error_already_set const &)
     {
-      PyObject *ptype, *pvalue, *ptraceback;
-      PyErr_Fetch (&ptype, &pvalue, &ptraceback);
-
-      try
-        {
-          std::string message = extract<std::string> (pvalue);
-          error ("pycall: %s", message.c_str ());
-        }
-      catch (error_already_set const &)
-        {
-          PyErr_Restore (ptype, pvalue, ptraceback);
-          PyErr_Print ();
-        }
+      std::string message = pytave::fetch_exception_message ();
+      error ("pycall: %s", message.c_str ());
     }
 
   return retval;
@@ -247,4 +236,8 @@
 %! assert (pycall ("pyfunc", true), 30)
 %! assert (pycall ("pyfunc", false), 20)
 %! assert (pycall ("pyfunc", 10), 10)
+
+%!error <NameError>
+%! pyexec ("def raiseException ():\n  raise NameError ('oops')")
+%! pycall ("raiseException")
 */
--- a/pyeval.cc	Fri Jul 15 00:51:23 2016 -0700
+++ b/pyeval.cc	Sat Jul 16 05:50:36 2016 -0700
@@ -86,19 +86,8 @@
     }
   catch (error_already_set const &)
     {
-      PyObject *ptype, *pvalue, *ptraceback;
-      PyErr_Fetch (&ptype, &pvalue, &ptraceback);
-
-      try
-        {
-          std::string message = extract<std::string> (pvalue);
-          error ("pyeval: %s", message.c_str ());
-        }
-      catch (error_already_set const &)
-        {
-          PyErr_Restore (ptype, pvalue, ptraceback);
-          PyErr_Print ();
-        }
+      std::string message = pytave::fetch_exception_message ();
+      error ("pyeval: %s", message.c_str ());
     }
 
   return retval;
@@ -139,4 +128,8 @@
 %! assert (z{2}{2}, 22)
 %! assert (z{4}{2}{1}, 421)
 %! assert (z{4}{2}{2}, 422)
+
+%!error <NameError>
+%! pyexec ("def raiseException ():\n  raise NameError ('oops')")
+%! pyeval ("raiseException ()")
 */
--- a/pyexec.cc	Fri Jul 15 00:51:23 2016 -0700
+++ b/pyexec.cc	Sat Jul 16 05:50:36 2016 -0700
@@ -81,19 +81,17 @@
     }
   catch (error_already_set const &)
     {
-      PyObject *ptype, *pvalue, *ptraceback;
-      PyErr_Fetch (&ptype, &pvalue, &ptraceback);
-
-      try
-        {
-          std::string message = extract<std::string> (pvalue);
-          error ("pyexec: %s", message.c_str ());
-        }
-      catch (error_already_set const &)
-        {
-          PyErr_Restore (ptype, pvalue, ptraceback);
-          PyErr_Print ();
-        }
+      std::string message = pytave::fetch_exception_message ();
+      error ("pyexec: %s", message.c_str ());
     }
   return retval;
 }
+
+/*
+%!error <NameError>
+%! pyexec ("raise NameError ('oops')")
+
+%!error <AttributeError>
+%! pyexec ("import sys")
+%! pyexec ("sys.no_such_thing")
+*/