C++ Exceptions in Python extensions
eric
eric at enthought.com
Wed Jan 16 16:10:35 EST 2002
Hello,
I'm stuck and would appreciate some eyeballs experienced with C++/Python. I
need to
know if the problem I am seeing extensions is a compiler
problem or a problem with weave (www.scipy.org/site_content/weave). Weave
uses
CXX in the C/C++ modules it generates and has been tested on W2K (MSVC and
gcc-
2.95.2), RH 7.1, BSD, and Solaris successfully. However, two sources
reported
errors on Mandrake 8.0 and 8.1 with gcc-2.96 installed (same compiler that
passes all tests on RH 7.1...) On Mandrake, weave extensions will produce
an
"Aborted" error for some situations:
[eric at manatee weave-0.2]$ python some_weave_test.py
--- TESTING ----
Aborted
After quite a bit of chasing, I've found that whenever I throw an exception
in a routine called by an extension method that is caught within the
extension
method, I get the Aborted error -- but only if the exception argument is a
"complex"
type such as a class. Integer exceptions work fine. For example:
# THIS WORKS
void throw_int() { throw 1; }
static PyObject* compiled_func(PyObject*self, PyObject* args)
{
try
{
throw_int();
}
catch( int val)
{
// WORKS
PyErr_SetString (PyExc_TypeError,"int exception caught");
}
return NULL
}
# THIS FAILS
void throw_class() { throw PWException(PyExc_TypeError,"class
exception"); }
static PyObject* compiled_func(PyObject*self, PyObject* args)
{
try
{
throw_int();
}
catch( PWException& e)
{
//FAILS
PyErr_SetString(PyExc_TypeError, e.What());
}
return NULL;
}
A test case using exceptions in a stand-alone C++ program passes without
errors
on Mandrake. I've boiled the problem down to a bare-bones test case that is
included. To try this out, put them in a directory and try:
python s2.py build_ext --inplace
The python test works at least on W2K and RH, but not on Mandrake. These
examples use SCXX style exceptions because I was trying different options.
The
same thing happens with CXX exceptions.
thanks for any insight you might have,
eric
################## W2K (MSVC) ##################
C:\home\ej\wrk\mandrake>python
Python 2.1.1 (#20, Jul 20 2001, 01:19:29) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
C:\home\ej\wrk\mandrake>python s2.py build_ext --inplace
running build_ext
building 'testfn2' extension
C:\Program Files\Microsoft Visual Studio\VC98\BIN\cl.exe /c /nologo /Ox /MD
/W3
/GX -IC:\Python21\Include /Tptestfn2.cxx /Fobuild\temp.win32-2.1\Release
\testfn2.obj
testfn2.cxx
testfn2.cxx(37) : warning C4101: 'val' : unreferenced local variable
C:\Program Files\Microsoft Visual Studio\VC98\BIN\link.exe /DLL /nologo
/INCREME
NTAL:NO /LIBPATH:C:\Python21\libs /EXPORT:inittestfn2
build\temp.win32-2.1\Relea
se\testfn2.obj /OUT:testfn2.pyd
/IMPLIB:build\temp.win32-2.1\Release\testfn2.lib
Creating library build\temp.win32-2.1\Release\testfn2.lib and object
build\te
mp.win32-2.1\Release\testfn2.exp
--- TESTING ----
caught exception: class exception
IT WORKED!
################## On RH 7.1 ##################
[ej at beowulf2 ~]$ python
Python 2.1.1 (#2, Sep 6 2001, 03:17:03)
[GCC 2.96 20000731 (Red Hat Linux 7.1 2.96-85)] on linux2
Type "copyright", "credits" or "license" for more information.
>>>
[ej at beowulf2 ~]$ cd mandrake
[ej at beowulf2 ~/mandrake]$ python s2.py build_ext --inplace
running build_ext
building 'testfn2' extension
creating build
creating build/temp.linux-i686-2.1
gcc -g -O2 -Wall -Wstrict-prototypes -fPIC
-I/home/emag/ej/include/python2.1 -c testfn2.cxx
-o build/temp.linux-i686-2.1/testfn2.o
g++ -shared build/temp.linux-i686-2.1/testfn2.o -o testfn2.so
--- TESTING ----
caught exception: class exception
IT WORKED!
################## On Mandrake ##################
[eric at manatee weave-0.2]$ python
Python 2.1.1 (#1, Dec 12 2001, 09:47:33)
[GCC 2.96 20000731 (Mandrake Linux 8.1 2.96-0.62mdk)] on linux2
[eric at manatee weave-0.2]$ ./a.out
PWException exceptionclass exception
IT WORKED!
[eric at manatee weave-0.2]$ python s2.py build_ext --inplace
running build_ext
building 'testfn2' extension
/usr/bin/gcc -O3 -minline-all-stringops -fomit-frame-pointer
-fPIC -I/usr/local/include/python2.1 -c testfn2.cxx
-o build/temp.linux-i686-2.1/testfn2.o
g++ -shared build/temp.linux-i686-2.1/testfn2.o -o testfn2.so
--- TESTING ----
Aborted
files:
------------------ s2.py -----------------------
#!/usr/bin/env python
import os,sys,glob
from distutils.core import setup, Extension
from distutils.unixccompiler import UnixCCompiler
import distutils.sysconfig
old_init_posix = distutils.sysconfig._init_posix
def _init_posix():
old_init_posix()
distutils.sysconfig._config_vars['LDSHARED'] = 'g++ -shared'
distutils.sysconfig._init_posix = _init_posix
if __name__ == '__main__':
ext = Extension('testfn2', ["testfn2.cxx"])
setup(name='testfn',ext_modules = [ext])
print
print '--- TESTING ----'
print
import testfn2
try:
testfn2.compiled_func(locals(),globals())
except TypeError, msg:
print 'caught exception:', msg
print 'IT WORKED!'
------------------ testfn2.cxx ------------------------
include "Python.h"
#include <string>
#include <string.h>
class PWException {
protected:
char m_msg[500];
PyObject* py_exception;
public:
PWException() : py_exception(0) { m_msg[0] = '\0';};
PWException(PyObject* exp, const char* msg) : py_exception(exp) {
strncpy(m_msg, msg, sizeof m_msg);
};
PWException(const char* msg) : py_exception(0) {
strncpy(m_msg, msg, sizeof m_msg);
};
PWException(const PWException& rhs) : py_exception(rhs.py_exception) {
strncpy(m_msg, rhs.What(), sizeof m_msg);
};
~PWException() {};
const char* What() const { return m_msg;};
};
void throw_int() { throw 1; }
void throw_string() { throw std::string("string exception"); }
void throw_class() { throw PWException(PyExc_TypeError,"class exception"); }
static PyObject* compiled_func(PyObject*self, PyObject* args)
{
// This will ALWAYS through a TypeError exception
try
{
//throw_int();
//throw_string();
throw_class();
}
catch( int val)
{
// WORKS
PyErr_SetString (PyExc_TypeError,"int exception caught");
}
catch( std::string& s)
{
// FAILS
PyErr_SetString (PyExc_TypeError,s.c_str());
}
catch( PWException& e)
{
//FAILS
PyErr_SetString(PyExc_TypeError, e.What());
}
return NULL;
}
static PyMethodDef compiled_methods[] =
{
{"compiled_func",(PyCFunction)compiled_func , METH_VARARGS},
{NULL, NULL} /* Sentinel */
};
extern "C" void inittestfn2()
{
(void) Py_InitModule("testfn2", compiled_methods);
}
----------------- test_alone.cxx -------------------
// [eric]$ This works on all 3 platforms.
// [eric]$ g++ test_alone.cxx
// [eric]$ ./a.out
// PWException exceptionclass exception
// IT WORKED!
#include <string>
#include <iostream>
#include <string.h>
class PWException {
protected:
char m_msg[500];
int* py_exception;
public:
PWException() : py_exception(0) { m_msg[0] = '\0';};
PWException(int* exp, const char* msg) : py_exception(exp) {
strncpy(m_msg, msg, sizeof m_msg);
};
PWException(const char* msg) : py_exception(0) {
strncpy(m_msg, msg, sizeof m_msg);
};
PWException(const PWException& rhs) : py_exception(rhs.py_exception) {
strncpy(m_msg, rhs.What(), sizeof m_msg);
};
~PWException() {};
const char* What() const { return m_msg;};
};
void throw_int() { throw 1; }
void throw_string() { throw std::string("string exception"); }
void throw_class() { throw PWException("class exception"); }
int main()
{
try
{
//throw_int();
// throw_string();
throw_class();
}
catch( PWException& e)
{
cout << "PWException exception" << e.What() << std::endl;
}
catch( std::string& msg)
{
cout << "std::string exception" << msg << std::endl;
}
catch( int msg)
{
cout << "int exception" << msg << std::endl;
}
cout << "IT WORKED!" << std::endl;
return 0;
}
------------------------------------------
--
Eric Jones <eric at enthought.com>
Enthought, Inc.
(512) 536-1057
More information about the Python-list
mailing list