I have some trouble handling custom C++ exceptions when calling from Cython.
My situation is the following: I have a library that uses CustomLibraryException for all exceptions. What I want is basically get the error message and raise a Python error with it.
The user guide has some hints but it is a bit unspecific.
The first possibility is to do:
cdef int bar() except +ValueError
This converts the CustomLibraryException to a ValueError, but loses the error message.
The other possibility is to explicitly convert the error using
cdef int raise_py_error()
cdef int something_dangerous() except +raise_py_error
I don't really understant this solution. I understood that raise_py_error has to be a C++ function that somehow handles the error. I am not sure how to handle it though. The function doesn't get an argument and is called inside the catch block in C++.
If any one has an working example of handling a C++ exception in Cython, that would be of great help.
Agreed the wording in the doc page leaves something to be desired. While "Cython cannot throw C++ exceptions", here is a raise_py_error that does what we want.
First, define the custom exception class in cython and make a handle to it using the "public" keyword
from cpython.ref cimport PyObject
class JMapError(RuntimeError):
pass
cdef public PyObject* jmaperror = <PyObject*>JMapError
Then write the exception handler (the docs aren't super clear this must be written in C++ and imported):
#include "Python.h"
#include "jmap/cy_utils.H"
#include "jmap/errors.H"
#include <exception>
#include <string>
using namespace std;
extern PyObject *jmaperror;
void raise_py_error()
{
try {
throw;
} catch (JMapError& e) {
string msg = ::to_string(e.code()) +" "+ e.what();
PyErr_SetString(jmaperror, msg.c_str());
} catch (const std::exception& e) {
PyErr_SetString(PyExc_RuntimeError, e.what() );
}
}
Finally, bring the handler into cython with an extern block, and use it:
cdef extern from "jmap/cy_utils.H":
cdef void raise_py_error()
void _connect "connect"() except +raise_py_error
Done. I now see new exception, constructed with the error code as intended:
JMapError: 520 timed connect failed: Connection refused
The default C++ exception handler in Cython should illustrate exactly how to accomplish what you are trying to do:
static void __Pyx_CppExn2PyErr() {
// Catch a handful of different errors here and turn them into the
// equivalent Python errors.
try {
if (PyErr_Occurred())
; // let the latest Python exn pass through and ignore the current one
else
throw;
} catch (const std::bad_alloc& exn) {
PyErr_SetString(PyExc_MemoryError, exn.what());
} catch (const std::bad_cast& exn) {
PyErr_SetString(PyExc_TypeError, exn.what());
} catch (const std::domain_error& exn) {
PyErr_SetString(PyExc_ValueError, exn.what());
} catch (const std::invalid_argument& exn) {
PyErr_SetString(PyExc_ValueError, exn.what());
} catch (const std::ios_base::failure& exn) {
// Unfortunately, in standard C++ we have no way of distinguishing EOF
// from other errors here; be careful with the exception mask
PyErr_SetString(PyExc_IOError, exn.what());
} catch (const std::out_of_range& exn) {
// Change out_of_range to IndexError
PyErr_SetString(PyExc_IndexError, exn.what());
} catch (const std::overflow_error& exn) {
PyErr_SetString(PyExc_OverflowError, exn.what());
} catch (const std::range_error& exn) {
PyErr_SetString(PyExc_ArithmeticError, exn.what());
} catch (const std::underflow_error& exn) {
PyErr_SetString(PyExc_ArithmeticError, exn.what());
} catch (const std::exception& exn) {
PyErr_SetString(PyExc_RuntimeError, exn.what());
}
catch (...)
{
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
}
So you can either #define __Pyx_CppExn2PyErr your_custom_exn_handler in an included .h file to override the generic behavior, or use a one-off custom handler as
cdef extern from "...":
void your_exn_throwing_fcn() except +your_custom_exn_handler
If CustomLibraryException derives from std::runtime_error (as a well-behaved C++ exception should), then the behavior you're seeing is a bug in Cython.
If it doesn't, then the easiest thing to do is to wrap the C++ function you're calling in a C++ helper function that translates the exception:
double foo(char const *, Bla const &); // this is the one we're wrapping
double foo_that_throws_runtime_error(char const *str, Bla const &blaref)
{
try {
return foo(str, blaref);
} catch (CustomLibraryException const &e) {
throw std::runtime_error(e.get_the_message());
}
}
This will cause a RuntimeError to be raised on the Python side. Alternatively, throw an std::invalid_argument to raise a ValueError, etc. (see the table in the page you linked to).
In Cython's sources, https://github.com/cython/cython/blob/master/tests/run/cpp_exceptions.pyx they actually implement the raise_py_error in a .pyx file. This makes it a lot easier to share error handling between other .pyx files.
A quick solution involves simply 2 files : myerror.pyx :
class MyError(RuntimeError):
"Base class for errors raised from my C++."
pass
cdef int raise_my_py_error() except *:
raise MyError("There was a problem")
and myerror.pxd :
cdef int raise_my_py_error() except *
which allows you to add an except +my_py_error in all your files.
However, this "loses" the e.what() of C++ exceptions. So a more interesting solution needs a couple more helper files :
my_error_helper.h :
extern const char* get_my_py_error_message();
my_error_helper.cxx :
#include <exception>
const char* get_my_py_error_message()
{
try {
throw;
} catch (const my_custom_cxx_exception& e) {
return e.what();
}
}
my_error_helper.pxd :
cdef extern from "my_error_helper.h":
const char* get_my_py_error_message()
my_error.pxd :
cdef int raise_my_py_error() except *
my_error.pyx :
cimport my_error_helper
class MyError(RuntimeError):
"Base class for errors raised from my C++."
pass
cdef int raise_my_py_error() except *:
msg = my_error_helper.get_my_py_error_message().decode('utf-8')
raise MyError(msg)
Related
I have a native C++ library and a SWIG-generated wrapper for C#. the .i file contains an %exception that wraps all the $actions inside regular try/catchblocks to convert exceptions to our desired target C# exceptions using SWIG_CSharpSetPendingExceptionCustom. Something like this
%exception {
try
{
$action
}
catch(const our::Exception& exc)
{
//blahblah
SWIG_CSharpSetPendingExceptionCustom(/*blah*/);
return $null;
}
catch(const std::exception& exc)
{
/*blah*/
}
catch(...)
{
/*blah*/
}
}
This works great, all regular C++ exceptions are nicely wrapped and forwarded to C#.
But what I also need is to wrap all my function with the SEH __try/__except blocks in order to catch potential access violations and whatnot and print the native stack trace. Something like
%exception {
__try
{
$action
}
__except(print_my_stack_trace(GetExceptionInformation()))
{
}
}
Unfortunately it is not allowed to combine regular try with SEH __try in one function in any way. So if my library has an arbitrary function myclass::f, what I would like to achieve is for SWIG to first create a f_temp function whose body will contain try/catch, then the true wrapper of f that would call f_temp wrapped with __try/__catch. The result for f would look something like
void SWIGSTDCALL CSharp_blah_myclass_f_TEMP__(void * jarg1) {
myclass *arg1 = (myclass *) 0 ;
arg1 = (myclass*)jarg1;
{
try
{
(arg1)->f();
}
catch(const our::Exception& exc)
{
...
SWIG_CSharpSetPendingExceptionCustom(...);
return ;
}
catch(const std::exception& exc)
{
...
}
}
SWIGEXPORT void SWIGSTDCALL CSharp_blah_myclass_f__(void * jarg1) {
__try
{
CSharp_blah_myclass_f_TEMP__(jarg1)
}
__except(print_my_stack)
{
}
}
I am thinking of resorting to writing a perl script that would manipulate the swig-generated wrapper .cpp file textually, but I first want to make sure that this is not possible to achieve with swig magic. So, can anyone think of a SWIG solution that does not involve ad-hoc manipulation of generated sources?
Currently within our API we have our own exception-type MyException which does not (neither directly nor indirectly) inherit from std::exception or any other type:
class MyException {
public:
MyException(std::string const& message);
std::string const& GetErrorMessage() const;
private:
//...stuff, e.g. like the error-message.
};
To our customers (and our own developers ) this leads the burden of always adding at least two catch-handler to a try-block:
try {
SomeLibraryFunction();
}
catch (MyException const& e) { std::cerr << e.GetErrorMessage(); }
catch (std::exception const& e) { std::cerr << e.what(); }
To reduce the number of catch-handler I would like to add inheritance from std::exception. But the problem with that is that it will "break" existing code. Namely the compiler will choose a different catch-handler than it did before:
try {
SomeOtherLibraryFunction();
}
catch(std::exception const& e) { std::cerr << "STD-EX"; }
catch(MyException const& e)
{
std::cerr << "LIBRARY-EX";
ExecuteMandatoryCodeWhenMyExceptionGetsThrown(e);
}
As soon as MyException inherits from std::exception the second catch-handler will never be reached. The reason for that is stated here:
When an exception of type E is thrown by any statement in compound-statement, it is matched against the types of the formal parameters T of each catch-clause in handler-seq, in the order in which the catch clauses are listed.
Is there a way that the compiler will take the catch-clause that is the best match instead of taking the first match? Or any other way to achieve the inheritance from std::exceptionwithout changing which catch-handler will be called?
The safest way is to change the exception type to a new type in this case, e.g. MyExceptionV2, educate people that it is much better, and that MyException is going to be deprecated eventually. Then give them time to upgrade their catch blocks to use your new type and remove the extra catch blocks. Then deprecate it in the next version, then remove MyException in the later version.
I'm using sqlite3pp to manipulate database. When I tried to insert one record twice in the same table by running,
sqlite3pp::command cmd(db, "INSERT INTO Groups (Name) VALUES (?)");
cmd.binder() << "Group_one";
cmd.execute();
it throwed an excpetion and showed me this:
libc++abi.dylib: terminating with uncaught exception of type
sqlite3pp::database_error: UNIQUE constraint failed: Groups.Name
But I'm not sure what type of exception should I use to catch? I tried
try {
cmd.execute();
} catch (std::exception& ex) {}
or
try {
cmd.execute();
} catch (sqlite3pp::database_error& ex) {}
or
try {
cmd.execute();
} catch (...) {}
But none of them work. Can anyone help me here? Thanks!
Here is my code:
#include <iostream>
#include "sqlite3pp.h"
int main(int argc, const char * argv[]) {
sqlite3pp::database db("./test.db");
// Create table
db.execute("CREATE TABLE IF NOT EXISTS Groups(" \
"Name TEXT PRIMARY KEY)");
sqlite3pp::command cmd(db, "INSERT INTO Groups (Name) VALUES (?)");
cmd.binder() << "Group_one";
try {
cmd.execute(); // When I run this code twice, the exception is thrown because of UNIQUE constraint.
} catch (std::exception& ex) {
std::cout << "exception: " << ex.what() << std::endl;
}
std::cout << "Done" << std::endl;
return 0;
}
I'm the writer of sqlite3pp and sorry for confusing you.
When I wrote this, I tried to make it very light weight. So, I decided not to translate all the sqlite3 error codes into c++ exceptions.
So, as a result, the methods have the integer type return value, which is the exact same error code that sqlite3 methods return. So, in this case, you need to check the return value of execute().
But, in some places, it cannot return the error code. e.g. in ctor and dtor. For these places, I introduced the database_error exception.
I would try to catch the exception type of the message ...
catch (sqlite3pp::database_error& ex)
{
...
}
I've look into the code and in the tests the developers use code like this:
#include "sqlite3pp.h"
try
{
sqlite3pp::command cmd(...);
cmd.execute();
}
catch (exception& ex) { // Note they use a reference here "exception&"
cout << ex.what() << endl;
}
so, you should use the same, if that doesn't work either, try to catch all using:
try {
cmd.execute();
} catch (...) {} // Using the ... should fix the error, but I recomend you to find the correct exception you have to catch.
Looking at the code closer
I have found the class (in sqlite3pp.h):
class database_error : public std::runtime_error
{
public:
explicit database_error(char const* msg);
explicit database_error(database& db);
};
So you should solve the problem using:
try {
cmd.execute();
} catch (database_error &e) {}
I was having this same issue - could not catch the exception no matter what I tried. However, after some digging I found out that C++11 declares destructors to be noexcept by default. I am using C++11 and was able to "fix" the issue by making the following change to the sqlite3pp code:
~transaction() noexcept(false);
transaction::~transaction() noexcept(false)
So, perhaps this is the issue the OP had?
Are there any conventions about which error numbers I should use in my C++ code?
Do I start at 1 or should I pick a high number and go from there?
An example was requested, so here it is:
#define ERR_EVERYTHING_IS_WRONG 42
try
{
throw ERR_EVERYTHING_IS_WRONG;
}
catch(int err)
{
//
}
For try-catch, do not use numbers! Use a class derived from a standard exception class. Example:
#include <stdexcept>
class my_error : public std::runtime_error {
public:
explicit my_error(const std::string& what_arg) : std::runtime_error(what_arg) {};
};
Usage (Coliru):
#include <iostream>
int main() {
try {
throw my_error("You can even pass a string here!");
} catch (const my_error& e) {
std::cerr << e.what();
}
}
Or simpler: use std::runtime_error
#include <stdexcept>
#include <iostream>
int main() {
try {
throw std::runtime_error("Error happened");
} catch (const std::runtime_error& e) {
std::cerr << e.what();
}
}
Without standard library:
class my_error {
};
int main() {
try {
throw my_error();
} catch (const my_error& e) {
//TODO handle my_error
}
}
One of the best way is to follow standard for conventions of different errors in C++ codes is Enum
eg:
enum FILE_ERROR{
FILE_NOT_FOUND,
FILE_NO_ACCESS,
FILE_BUSY
};
so in code u can use FILE_NOT_FOUND as error number which is 0 . So this makes easy to understand what error type stands for what
There is no rule, you can do whatever you want as long as you keep a logical way to assign it.
If you choose 3 for bad user input, keep it for only that error or you'll get lost really soon
In C++ it is common to have 1 as success and 0 as error code, unlikely to C, where there are many functions returning 0 as success (strcmp, etc...)
this may be confusing sometimes, especially when interacting with C code, however I find that it helps a lot readability.
if(cplusplus_function()) {...}
is a lot more readable than
if(!c_function()){ ... }
remember also that you have exceptions to leverage in C++, and try to avoid nesting if-s
You don't "throw" any number, you "throw" an exception, an object of a class that derives from std::exception.
Standard exceptions contain text, and do not actually contain an error number. You can however create different classes for different types of exceptions, and have different catch handlers dependent on which exception type was thrown.
I'm developing a C api for some functionality written in C++ and I want to make sure that no exceptions are propagated out of any of the exported C functions.
The simple way to do it is making sure each exported function is contained in a:
try {
// Do the actual code
} catch (...) {
return ERROR_UNHANDLED_EXCEPTION;
}
Let's say I know one exception that is often missed inside the C++ code is std::bad_alloc and I want to treat it specially I'd write something like this instead:
try {
// Run the actual code
} catch (std::bad_alloc& e) {
return ERROR_BAD_ALLOC;
} catch (...) {
return ERROR_UNHANDLED_EXCEPTION;
}
Is it possible to decompose this in some clever way so that I can globally treat some errors differently without adding a new catch statement for the exception handler around every exported function?
I'm aware of that this is possible to solve using the preprocessor, but before going down that road, I'd make sure there is no other way to do it.
You can use only one handler function for all possible exceptions, and call it from each or your API implementation functions, as below:
int HandleException()
{
try
{
throw;
}
// TODO: add more types of exceptions
catch( std::bad_alloc & )
{
return ERROR_BAD_ALLOC;
}
catch( ... )
{
return ERROR_UNHANDLED_EXCEPTION;
}
}
And in each exported function:
try
{
...
}
catch( ... )
{
return HandleException();
}
There already is a good answer. But just FYI, its called 'exception-dispatcher' idiom, see C++ FAQ.
What about:
try{
//Your code here
} catch(std::exception e)
{
return translateExceptionToErrorCode(e);
} catch(...)
{
return UNKNOWN_EXCEPTION_THROWN;
}
Jem answer is a little more simpler than this solution. But it is possible to substitute the use of a preprocessor macro with the use of templates. Something like this (more refinements you could made):
template <class T, void (T::*FUNC)()>
class CatchWrapper
{
public:
static void WrapCall(T* instance)
{
try
{
(instance->*FUNC)();
}
catch (std::bad_alloc&)
{
// Do Something 1
}
catch (std::exception& e)
{
// Do Something 2
}
catch (...)
{
// Do Something 3
}
}
};
class Foo
{
public:
void SomeCall()
{
std::cout << "Do Something" << std::endl;
}
};
int main(int argc, char* argv[])
{
Foo i;
CatchWrapper<Foo, &Foo::SomeCall>::WrapCall(&i);
return 0;
}
Do not ever use catch(...), unless you plan on more or less immediately re-throwing. You will certainly lost any error information you might have had to help you figure out the cause of the error.
I like your second scheme a little better - catch a known set of exceptions, ideally because they are the only ones your code will throw, and let the rest through - allowing the app to crash is possibly the best thing to do since you have invoked unknown behaviour it is best to "crash responsibly".
It would be a shame to loose error information at the language boundary. You really should try to translate all exceptions into an error code usable from C.
How you do it really depends on what your exception classes look like. If you control your exception class hierarchy, you can ensure that each class provides a translation using a virtual method. If not, you may still find it practical to use a translator function and test the types of the 'std::exception'-derived exception it receives to translate it into an error code, much like Jem suggested (remember: thrown exceptions will hurt performance anyway, so don't worry about the translation being slow).