1

After reading an excellent answer on Dynamically rethrowing self-defined C++ exceptions as Python exceptions using SWIG, I am trying to throw a custom Exception from C++ and catch it in Python. I have tried to build the simplest example, so that I can see what I'm doing wrong. I would appreciate some help here.

I've started by creating a class called Example which has one method. In this method, I always throw my Exception which extends the Exception base class in C++. This exception is declared in the header.

I'm trying to catch this Exception in Python but so far I am unable to get this to compile. I tried some of the other solutions in the thread mentioned aboved, and while they compiled, I did not seem to be able to catch the Exception without Python aborting.

Here's what I have so far (a very basic project)

example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

#include <string>
#include <exception>

class Example
{
public:
    std::string getName();

};

class ExampleException
{
public:
    ExampleException(const std::string &what) { this->eMsg == (std::string(what)); }
    const char * what() const throw() { return eMsg.c_str(); }
private:
    std::string eMsg;
};

#endif // EXAMPLE_H

example.cpp

#include "example.h"
#include "exception"

using namespace std;


std::string Example::getName()
{
   /* Always throw an exception just so we can test this */
   throw ExampleException("Couldn't find a name");
   return("John");
}

example.i

%module example
%include "example.i"
%include exception.i

%init %{
    m_ExampleException = PyErr_NewException("_example.ExampleException", NULL, NULL);
    Py_INCREF(m_ExampleException);
    PyModule_AddObject(m, "ExampleException", m_ExampleException);
%}

%exception {
    try {
        $action
    } catch (ExampleException &e) {
PyErr_SetString(ExampleException, const_cast<char*>(e.what()));
    SWIG_fail;
    }
}

%{
    #include "example.h"
    #define SWIG_FILE_WITH_INIT
    static PyObject* m_ExampleException;
%}

test.py

import example

try:
   print example.Example_getName()
except ExampleException as e:
   print e.what()

And I run the following commands to build the project:

swig -verbose -python -c++ example.i
g++ -fPIC -c example_wrap.cxx -I/usr/include/python2.7 -o example_wrap.o -fPIC
g++ -c example.cpp -I/usr/include/python2.7 -fPIC
g++ -shared example_wrap.o example.o -o _example.so

Unfortunately, I am given the following error message as well as a warning:

example_wrap.cxx: In function ‘void init_example()’:
example_wrap.cxx:3839:82: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
m_ExampleException = PyErr_NewException("_example.ExampleException", NULL, NULL);
                                                                              ^
In file included from /usr/include/python2.7/Python.h:80:0,
             from example_wrap.cxx:171:
/usr/include/python2.7/object.h:769:20: error: expected primary-expression before ‘)’ token
 ((PyObject*)(op))->ob_refcnt++)

I feel like I'm missing something obvious and would appreciate an extra pair of eyes. I have not used SWIG and C++ together extensively before.

Thanks for your time

Community
  • 1
  • 1
user3526827
  • 153
  • 1
  • 1
  • 9
  • 1
    The name of the static `PyObject*` in the `PyINCREF()` call should be `m_ExampleException`. Also, your `%include "example.i"` should be `%include "example.h"` and come **after** the `%exception` directive. But why don't you follow the answer given to the question you linked, i.e., let your custom exception inherit from `std::exception`, let SWIG wrap this exception in Python, and throw this wrapped exception in Python as the equivalent to the C++ exception? – m7thon May 24 '16 at 21:14
  • Hi -- I tried some of the examples in the thread I linked to, but they did not work properly. I also read that the method you mentioned generally workd well, but not necessarily in Python. Thanks kindly for your reply -- I'll let you know how I get on. – user3526827 May 24 '16 at 23:34
  • Okay -- I've tried that, it now compiles,but I'm faced with the same situation I had with some other methods. terminate called after throwing an instance of 'ExampleException'' Aborted I have tried commenting out SWIG_FAIL in the %exception directive, but it's still not working. My Python code is a simple try; except exception as e: print e.what(). – user3526827 May 24 '16 at 23:37
  • Your code still shouldn't compile, since the `ExampleException` in the call to `PyErr_SetString` needs to be `m_ExampleException` as well. Are you sure you put the `%include "example.h"` directive last in the interface file? I just tried it, and for me the throwing and catching of the exception works. – m7thon May 25 '16 at 08:00
  • After amending m_ExampleException, I can get it to compile. I updated my post to reflect the changes. I have also amended PyErr_SetString, but it did compile without referring to m_ExampleException. – user3526827 May 25 '16 at 12:33
  • Even with your suggested changes, I'm not having any luck. I've updated my first post to show the Python code I'm trying to use. Now I get ExampleException is not defined and also told the getName method doesn't exist. I really appreciate the guidance you've given me. I'll keep trying to get this to work. – user3526827 May 25 '16 at 12:41
  • Sigh. You didn't follow the suggestions at all. (1) Move the `%{...%}` code back up (above the `%init %{...` code). (2) Move the line `%include "example.i"` to the bottom and change it to `%include "example.h"`. (3) Change `PyErr_SetString(ExampleException, ...` to `PyErr_SetString(m_ExampleException, ...`. – m7thon May 25 '16 at 15:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/112941/discussion-between-m7thon-and-user3526827). – m7thon May 25 '16 at 15:58
  • Does `ExampleException` deliberately not inherit from `std::exception`? – Flexo May 28 '16 at 21:43
  • I know this was years ago, but if the `ExampleException` constructor really contained: `this->eMsg == (std::string(what));` then that was your problem right there. (And you probably weren't compiling with warnings on, because a decent compiler would catch an equality-test-vs-assignment error. – FeRD Jun 02 '22 at 19:28

0 Answers0