diff --git a/cMake/FindPyCXX.cmake b/cMake/FindPyCXX.cmake index 8de77eebf7..1b703e967a 100644 --- a/cMake/FindPyCXX.cmake +++ b/cMake/FindPyCXX.cmake @@ -117,7 +117,7 @@ if(PYCXX_FOUND) ${PYCXX_SOURCE_DIR}/cxxsupport.cxx ${PYCXX_SOURCE_DIR}/IndirectPythonInterface.cxx ) - if(NOT ${PYCXX_VERSION} VERSION_LESS 7.0.0) + if(NOT ${PYCXX_VERSION} VERSION_LESS 6.3.0) list(APPEND PYCXX_SOURCES ${PYCXX_SOURCE_DIR}/cxx_exceptions.cxx) add_definitions(-DPYCXX_6_2_COMPATIBILITY) diff --git a/src/CXX/Python3/Config.hxx b/src/CXX/Python3/Config.hxx index 57841335ed..5b5802c57d 100644 --- a/src/CXX/Python3/Config.hxx +++ b/src/CXX/Python3/Config.hxx @@ -71,11 +71,16 @@ // Which C++ standard is in use? // #if defined( _MSC_VER ) - +# if _MSC_VER <= 1200 +// MSVC++ 6.0 +# define PYCXX_ISO_CPP_LIB 0 +# define STR_STREAM +# define TEMPLATE_TYPENAME class +# else # define PYCXX_ISO_CPP_LIB 1 # define STR_STREAM # define TEMPLATE_TYPENAME typename - +# endif #elif defined( __GNUC__ ) # if __GNUC__ >= 3 # define PYCXX_ISO_CPP_LIB 1 diff --git a/src/CXX/Python3/Exception.hxx b/src/CXX/Python3/Exception.hxx index 1b558dc4ce..c337fc3018 100644 --- a/src/CXX/Python3/Exception.hxx +++ b/src/CXX/Python3/Exception.hxx @@ -62,200 +62,58 @@ namespace Py explicit Exception () {} - + // This overloaded constructor will be removed in future PyCXX versions //Exception (const std::string &reason) //{ // PyErr_SetString( Py::_Exc_RuntimeError(), reason.c_str() ); //} - + Exception( PyObject *exception, const std::string &reason ) { PyErr_SetString( exception, reason.c_str() ); } - - Exception( PyObject *exception, Object &reason ); + + Exception( PyObject *exception, Object &reason ); void clear() // clear the error // technically but not philosophically const { PyErr_Clear(); } + + // is the exception this specific exception 'exc' + bool matches( ExtensionExceptionType &exc ); }; - - + + // for user defined exceptions to be made know to pycxx + typedef void (*throw_exception_func_t)( void ); + void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t throw_func ); + // Abstract class PYCXX_EXPORT StandardError: public Exception { - protected: + protected: explicit StandardError() {} }; - - class PYCXX_EXPORT LookupError: public StandardError - { - protected: - explicit LookupError() - {} - }; - - class PYCXX_EXPORT ArithmeticError: public StandardError - { - protected: - explicit ArithmeticError() - {} - }; - - class PYCXX_EXPORT EnvironmentError: public StandardError - { - protected: - explicit EnvironmentError() - {} - }; - - // Concrete - - class PYCXX_EXPORT TypeError: public StandardError - { - public: - TypeError (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_TypeError(),reason.c_str() ); - } - }; - - class PYCXX_EXPORT IndexError: public LookupError - { - public: - IndexError (const std::string& reason) - : LookupError() - { - PyErr_SetString( Py::_Exc_IndexError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT AttributeError: public StandardError - { - public: - AttributeError (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_AttributeError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT NameError: public StandardError - { - public: - NameError (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_NameError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT RuntimeError: public StandardError - { - public: - RuntimeError (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_RuntimeError(), reason.c_str() ); - } - }; - - class NotImplementedError: public StandardError - { - public: - NotImplementedError (const std::string& reason) - : StandardError() - { - PyErr_SetString (Py::_Exc_NotImplementedError(), reason.c_str()); - } - }; - - class PYCXX_EXPORT SystemError: public StandardError - { - public: - SystemError (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_SystemError(),reason.c_str() ); - } - }; - - class PYCXX_EXPORT KeyError: public LookupError - { - public: - KeyError (const std::string& reason) - : LookupError() - { - PyErr_SetString( Py::_Exc_KeyError(),reason.c_str() ); - } - }; - - - class PYCXX_EXPORT ValueError: public StandardError - { - public: - ValueError (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_ValueError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT OverflowError: public ArithmeticError - { - public: - OverflowError (const std::string& reason) - : ArithmeticError() - { - PyErr_SetString( Py::_Exc_OverflowError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT ZeroDivisionError: public ArithmeticError - { - public: - ZeroDivisionError (const std::string& reason) - : ArithmeticError() - { - PyErr_SetString( Py::_Exc_ZeroDivisionError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT FloatingPointError: public ArithmeticError - { - public: - FloatingPointError (const std::string& reason) - : ArithmeticError() - { - PyErr_SetString( Py::_Exc_FloatingPointError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT MemoryError: public StandardError - { - public: - MemoryError (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_MemoryError(), reason.c_str() ); - } - }; - - class PYCXX_EXPORT SystemExit: public StandardError - { - public: - SystemExit (const std::string& reason) - : StandardError() - { - PyErr_SetString( Py::_Exc_SystemExit(),reason.c_str() ); - } - }; +#define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ + class PYCXX_EXPORT eclass : public bclass \ + { \ + public: \ + eclass() {} \ + eclass( const char *reason ) { PyErr_SetString( _Exc_##eclass(), reason ); } \ + eclass( const std::string &reason ) { PyErr_SetString( _Exc_##eclass(), reason.c_str() ); } \ + ~eclass() {} \ + \ + static void throwFunc() { throw eclass(); } \ + static PyObject *exceptionType() { return _Exc_##eclass(); } \ + }; \ + +#include + +#undef PYCXX_STANDARD_EXCEPTION }// Py #endif diff --git a/src/CXX/Python3/Objects.hxx b/src/CXX/Python3/Objects.hxx index 37f17a6c78..aae03fc00a 100644 --- a/src/CXX/Python3/Objects.hxx +++ b/src/CXX/Python3/Objects.hxx @@ -54,6 +54,8 @@ namespace Py { + void ifPyErrorThrowCxxException(); + typedef Py_ssize_t sequence_index_type; // type of an index into a sequence PYCXX_EXPORT Py_ssize_t numeric_limits_max(); @@ -3169,7 +3171,7 @@ namespace Py PyObject *result = PyObject_CallObject( ptr(), args.ptr() ); if( result == NULL ) { - throw Exception(); + ifPyErrorThrowCxxException(); } return asObject( result ); } @@ -3184,7 +3186,7 @@ namespace Py #endif if( result == NULL ) { - throw Exception(); + ifPyErrorThrowCxxException(); } return asObject( result ); } diff --git a/src/CXX/Python3/cxx_exceptions.cxx b/src/CXX/Python3/cxx_exceptions.cxx new file mode 100644 index 0000000000..906133ac48 --- /dev/null +++ b/src/CXX/Python3/cxx_exceptions.cxx @@ -0,0 +1,72 @@ +// +// cxx_exceptions.cxx +// +#include +#include + +#include + +namespace Py +{ +typedef void (*throw_exception_func_t)( void ); + +std::map py_exc_type_to_exc_func; + +void addPythonException( ExtensionExceptionType &py_exc_type, throw_exception_func_t func ) +{ + py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type.ptr(), func ) ); +} + +void addPythonException( PyObject *py_exc_type, throw_exception_func_t func ) +{ + py_exc_type_to_exc_func.insert( std::make_pair( py_exc_type, func ) ); +} + +void ifPyErrorThrowCxxException() +{ + if( PyErr_Occurred() ) + { + PyObject *ptype, *pvalue, *ptrace; + PyErr_Fetch( &ptype, &pvalue, &ptrace ); + PyErr_Restore( ptype, pvalue, ptrace ); + + Object q( ptype ); + + std::map::iterator func = py_exc_type_to_exc_func.find( ptype ); + if( func != py_exc_type_to_exc_func.end() ) + { +#ifdef PYCXX_DEBUG + std::cout << "ifPyErrorThrowCxxException found throwFunc: " << q << std::endl; +#endif + (func->second)(); + } + else + { +#ifdef PYCXX_DEBUG + std::cout << "ifPyErrorThrowCxxException no throwFunc: " << q << std::endl; +#endif + throw Exception(); + } + } +} + +void initExceptions() +{ + static bool init_done = false; + if( init_done ) + { + return; + } + +#define PYCXX_STANDARD_EXCEPTION( eclass, bclass ) \ + addPythonException( eclass::exceptionType(), eclass::throwFunc ); + +#include + +#undef PYCXX_STANDARD_EXCEPTION + + init_done = true; +} + + +} // end of namespace Py diff --git a/src/CXX/Python3/cxx_extensions.cxx b/src/CXX/Python3/cxx_extensions.cxx index 30ac303112..34e57fb8ba 100644 --- a/src/CXX/Python3/cxx_extensions.cxx +++ b/src/CXX/Python3/cxx_extensions.cxx @@ -36,6 +36,7 @@ //----------------------------------------------------------------------------- #include "CXX/Extensions.hxx" #include "CXX/Exception.hxx" +#include "CXX/Objects.hxx" #include @@ -77,10 +78,10 @@ void Object::validate() } #endif release(); - if( PyErr_Occurred() ) - { // Error message already set - throw Exception(); - } + + // If error message already set + ifPyErrorThrowCxxException(); + // Better error message if RTTI available #if defined( _CPPRTTI ) || defined( __GNUG__ ) throw TypeError( s ); @@ -183,8 +184,13 @@ public: ExtensionModuleBase *module; }; +void initExceptions(); + void ExtensionModuleBase::initialize( const char *module_doc ) { + // init the exception code + initExceptions(); + memset( &m_module_def, 0, sizeof( m_module_def ) ); m_module_def.m_name = const_cast( m_module_name.c_str() ); @@ -1644,6 +1650,12 @@ void ExtensionExceptionType::init( ExtensionModuleBase &module, const std::strin set( PyErr_NewException( const_cast( module_name.c_str() ), parent.ptr(), NULL ), true ); } +// is the exception this specific exception 'exc' +bool Exception::matches( ExtensionExceptionType &exc ) +{ + return PyErr_ExceptionMatches( exc.ptr() ) != 0; +} + ExtensionExceptionType::~ExtensionExceptionType() { } diff --git a/src/CXX/Python3/cxx_standard_exceptions.hxx b/src/CXX/Python3/cxx_standard_exceptions.hxx new file mode 100644 index 0000000000..4bf2ca0bd9 --- /dev/null +++ b/src/CXX/Python3/cxx_standard_exceptions.hxx @@ -0,0 +1,21 @@ +#if !defined( PYCXX_STANDARD_EXCEPTION ) +#pragma error( "define PYCXX_STANDARD_EXCEPTION before including" ) +#endif + +PYCXX_STANDARD_EXCEPTION( LookupError, StandardError ) +PYCXX_STANDARD_EXCEPTION( ArithmeticError, StandardError ) +PYCXX_STANDARD_EXCEPTION( EnvironmentError, StandardError ) +PYCXX_STANDARD_EXCEPTION( TypeError, StandardError ) +PYCXX_STANDARD_EXCEPTION( IndexError, LookupError ) +PYCXX_STANDARD_EXCEPTION( AttributeError, StandardError ) +PYCXX_STANDARD_EXCEPTION( NameError, StandardError ) +PYCXX_STANDARD_EXCEPTION( RuntimeError, StandardError ) +PYCXX_STANDARD_EXCEPTION( NotImplementedError, StandardError ) +PYCXX_STANDARD_EXCEPTION( SystemError, StandardError ) +PYCXX_STANDARD_EXCEPTION( KeyError, LookupError ) +PYCXX_STANDARD_EXCEPTION( ValueError, StandardError ) +PYCXX_STANDARD_EXCEPTION( OverflowError, ArithmeticError ) +PYCXX_STANDARD_EXCEPTION( ZeroDivisionError, ArithmeticError ) +PYCXX_STANDARD_EXCEPTION( FloatingPointError, ArithmeticError ) +PYCXX_STANDARD_EXCEPTION( MemoryError, StandardError ) +PYCXX_STANDARD_EXCEPTION( SystemExit, StandardError ) diff --git a/src/CXX/Python3/cxxsupport.cxx b/src/CXX/Python3/cxxsupport.cxx index 681bea634e..3439306b7d 100644 --- a/src/CXX/Python3/cxxsupport.cxx +++ b/src/CXX/Python3/cxxsupport.cxx @@ -91,48 +91,42 @@ String Bytes::decode( const char *encoding, const char *error ) bool operator==( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_EQ ); - if( PyErr_Occurred() ) - throw Exception(); + ifPyErrorThrowCxxException(); return k != 0; } bool operator!=( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_NE ); - if( PyErr_Occurred() ) - throw Exception(); + ifPyErrorThrowCxxException(); return k != 0; } bool operator>=( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_GE ); - if( PyErr_Occurred() ) - throw Exception(); + ifPyErrorThrowCxxException(); return k != 0; } bool operator<=( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_LE ); - if( PyErr_Occurred() ) - throw Exception(); + ifPyErrorThrowCxxException(); return k != 0; } bool operator<( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_LT ); - if( PyErr_Occurred() ) - throw Exception(); + ifPyErrorThrowCxxException(); return k != 0; } bool operator>( const Object &o1, const Object &o2 ) { int k = PyObject_RichCompareBool( *o1, *o2, Py_GT ); - if( PyErr_Occurred() ) - throw Exception(); + ifPyErrorThrowCxxException(); return k != 0; } diff --git a/src/CXX/Version.hxx b/src/CXX/Version.hxx index cdca519320..67f2ca9454 100644 --- a/src/CXX/Version.hxx +++ b/src/CXX/Version.hxx @@ -39,8 +39,8 @@ #define __PyCXX_version_hxx__ #define PYCXX_VERSION_MAJOR 6 -#define PYCXX_VERSION_MINOR 2 -#define PYCXX_VERSION_PATCH 8 +#define PYCXX_VERSION_MINOR 3 +#define PYCXX_VERSION_PATCH 0 #define PYCXX_MAKEVERSION( major, minor, patch ) ((major<<16)|(minor<<8)|(patch)) #define PYCXX_VERSION PYCXX_MAKEVERSION( PYCXX_VERSION_MAJOR, PYCXX_VERSION_MINOR, PYCXX_VERSION_PATCH ) #endif diff --git a/src/CXX/cxx_exceptions.cxx b/src/CXX/cxx_exceptions.cxx new file mode 100644 index 0000000000..60e8767db9 --- /dev/null +++ b/src/CXX/cxx_exceptions.cxx @@ -0,0 +1,7 @@ +#include "CXX/WrapPython.h" + +#if PY_MAJOR_VERSION == 2 +#include "Python2/cxx_exceptions.cxx" +#else +#include "Python3/cxx_exceptions.cxx" +#endif