From 59417068f5a34d3bf61c2c2c95dc9a081c18fbad Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Fri, 21 Jun 2019 10:46:43 +0800 Subject: [PATCH] Base: improve exception For better FC and Python exception mapping. --- src/App/Application.cpp | 8 ++ src/Base/Exception.cpp | 181 +++++++++++++++++++++++++++----------- src/Base/Exception.h | 60 ++++++++++++- src/Base/Interpreter.cpp | 58 +++++++++--- src/Base/Interpreter.h | 5 ++ src/Base/PyObjectBase.cpp | 1 + src/Base/PyObjectBase.h | 75 ++++++++-------- src/Base/PyTools.c | 32 ++++++- src/Base/PyTools.h | 1 + 9 files changed, 311 insertions(+), 110 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index a464b667aa3a..9ac487438022 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -194,6 +194,7 @@ Base::ConsoleObserverFile *Application::_pConsoleObserverFile =0; AppExport std::map Application::mConfig; BaseExport extern PyObject* Base::BaseExceptionFreeCADError; +BaseExport extern PyObject* Base::BaseExceptionFreeCADAbort; //************************************************************************** // Construction and destruction @@ -314,6 +315,10 @@ Application::Application(std::map &mConfig) Py_INCREF(Base::BaseExceptionFreeCADError); PyModule_AddObject(pBaseModule, "FreeCADError", Base::BaseExceptionFreeCADError); + Base::BaseExceptionFreeCADAbort = PyErr_NewException("Base.FreeCADAbort", PyExc_BaseException, NULL); + Py_INCREF(Base::BaseExceptionFreeCADAbort); + PyModule_AddObject(pBaseModule, "FreeCADAbort", Base::BaseExceptionFreeCADAbort); + // Python types Base::Interpreter().addType(&Base::VectorPy ::Type,pBaseModule,"Vector"); Base::Interpreter().addType(&Base::MatrixPy ::Type,pBaseModule,"Matrix"); @@ -1319,6 +1324,7 @@ void Application::initTypes(void) Base::Type ::init(); Base::BaseClass ::init(); Base::Exception ::init(); + Base::AbortException ::init(); Base::Persistence ::init(); // Complex data classes @@ -1461,6 +1467,8 @@ void Application::initTypes(void) new ExceptionProducer; new ExceptionProducer; new ExceptionProducer; + new ExceptionProducer; + new ExceptionProducer; new ExceptionProducer; new ExceptionProducer; new ExceptionProducer; diff --git a/src/Base/Exception.cpp b/src/Base/Exception.cpp index de1ad2aca7b5..b1e58ff7ce31 100644 --- a/src/Base/Exception.cpp +++ b/src/Base/Exception.cpp @@ -31,6 +31,8 @@ #include "Console.h" #include +FC_LOG_LEVEL_INIT("Exception", true, true); + using namespace Base; @@ -88,32 +90,17 @@ const char* Exception::what(void) const throw() void Exception::ReportException (void) const { if (!_isReported) { - std::string str = ""; - - if (!_sErrMsg.empty()) - str+= (_sErrMsg + " "); - - if (!_function.empty()) { - str+="In "; - str+=_function; - str+= " "; - } - - std::string _linestr = std::to_string(_line); - - if (!_file.empty() && !_linestr.empty()) { - // strip absolute path - std::size_t pos = _file.find("src"); - - if (pos!=std::string::npos) { - str+="in "; - str+= _file.substr(pos); - str+= ":"; - str+=_linestr; - } - } - - Console().Error("Exception (%s): %s \n",Console().Time(),str.c_str()); + const char *msg; + if(_sErrMsg.empty()) + msg = typeid(*this).name(); + else + msg = _sErrMsg.c_str(); +#ifdef FC_DEBUG + if(_function.size()) { + _FC_ERR(_file.c_str(),_line, _function << " -- " << msg); + }else +#endif + _FC_ERR(_file.c_str(),_line,msg); _isReported = true; } } @@ -164,6 +151,7 @@ void Exception::setPyObject( PyObject * pydict) // --------------------------------------------------------- +TYPESYSTEM_SOURCE(Base::AbortException,Base::Exception); AbortException::AbortException(const char * sMessage) : Exception( sMessage ) @@ -315,32 +303,17 @@ const char* FileException::what() const throw() void FileException::ReportException (void) const { if (!_isReported) { - std::string str = ""; - - if (!_sErrMsgAndFileName.empty()) - str+= (_sErrMsgAndFileName + " "); - - if (!_function.empty()) { - str+="In "; - str+=_function; - str+= " "; - } - - std::string _linestr = std::to_string(_line); - - if (!_file.empty() && !_linestr.empty()) { - // strip absolute path - std::size_t pos = _file.find("src"); - - if (pos!=std::string::npos) { - str+="in "; - str+= _file.substr(pos); - str+= ":"; - str+=_linestr; - } - } - - Console().Error("Exception (%s): %s \n",Console().Time(),str.c_str()); + const char *msg; + if(_sErrMsgAndFileName.empty()) + msg = typeid(*this).name(); + else + msg = _sErrMsgAndFileName.c_str(); +#ifdef FC_DEBUG + if(_function.size()) { + _FC_ERR(_file.c_str(),_line, _function << " -- " << msg); + }else +#endif + _FC_ERR(_file.c_str(),_line,msg); _isReported = true; } } @@ -363,6 +336,10 @@ void FileException::setPyObject( PyObject * pydict) } } +PyObject * FileException::getPyExceptionType() const { + return PyExc_IOError; +} + // --------------------------------------------------------- @@ -544,6 +521,10 @@ TypeError::TypeError(const TypeError &inst) { } +PyObject *TypeError::getPyExceptionType() const { + return PyExc_TypeError; +} + // --------------------------------------------------------- ValueError::ValueError() @@ -566,6 +547,10 @@ ValueError::ValueError(const ValueError &inst) { } +PyObject *ValueError::getPyExceptionType() const { + return PyExc_ValueError; +} + // --------------------------------------------------------- IndexError::IndexError() @@ -588,6 +573,62 @@ IndexError::IndexError(const IndexError &inst) { } +PyObject *IndexError::getPyExceptionType() const { + return PyExc_IndexError; +} + +// --------------------------------------------------------- + +NameError::NameError() + : Exception() +{ +} + +NameError::NameError(const char * sMessage) + : Exception(sMessage) +{ +} + +NameError::NameError(const std::string& sMessage) + : Exception(sMessage) +{ +} + +NameError::NameError(const NameError &inst) + : Exception(inst) +{ +} + +PyObject *NameError::getPyExceptionType() const { + return PyExc_NameError; +} + +// --------------------------------------------------------- + +ImportError::ImportError() + : Exception() +{ +} + +ImportError::ImportError(const char * sMessage) + : Exception(sMessage) +{ +} + +ImportError::ImportError(const std::string& sMessage) + : Exception(sMessage) +{ +} + +ImportError::ImportError(const ImportError &inst) + : Exception(inst) +{ +} + +PyObject *ImportError::getPyExceptionType() const { + return PyExc_ImportError; +} + // --------------------------------------------------------- AttributeError::AttributeError() @@ -610,6 +651,10 @@ AttributeError::AttributeError(const AttributeError &inst) { } +PyObject *AttributeError::getPyExceptionType() const { + return PyExc_AttributeError; +} + // --------------------------------------------------------- RuntimeError::RuntimeError() @@ -632,6 +677,10 @@ RuntimeError::RuntimeError(const RuntimeError &inst) { } +PyObject *RuntimeError::getPyExceptionType() const { + return PyExc_RuntimeError; +} + // --------------------------------------------------------- BadGraphError::BadGraphError() @@ -676,6 +725,10 @@ NotImplementedError::NotImplementedError(const NotImplementedError &inst) { } +PyObject *NotImplementedError::getPyExceptionType() const { + return PyExc_NotImplementedError; +} + // --------------------------------------------------------- DivisionByZeroError::DivisionByZeroError() @@ -698,6 +751,10 @@ DivisionByZeroError::DivisionByZeroError(const DivisionByZeroError &inst) { } +PyObject *DivisionByZeroError::getPyExceptionType() const { + return PyExc_ZeroDivisionError; +} + // --------------------------------------------------------- ReferencesError::ReferencesError() @@ -720,6 +777,10 @@ ReferencesError::ReferencesError(const ReferencesError &inst) { } +PyObject *ReferencesError::getPyExceptionType() const { + return PyExc_ReferenceError; +} + // --------------------------------------------------------- ExpressionError::ExpressionError() @@ -786,6 +847,10 @@ UnicodeError::UnicodeError(const UnicodeError &inst) { } +PyObject *UnicodeError::getPyExceptionType() const { + return PyExc_UnicodeError; +} + // --------------------------------------------------------- OverflowError::OverflowError() @@ -808,6 +873,10 @@ OverflowError::OverflowError(const OverflowError &inst) { } +PyObject *OverflowError::getPyExceptionType() const { + return PyExc_OverflowError; +} + // --------------------------------------------------------- UnderflowError::UnderflowError() @@ -830,6 +899,10 @@ UnderflowError::UnderflowError(const UnderflowError &inst) { } +PyObject *UnderflowError::getPyExceptionType() const { + return PyExc_ArithmeticError; +} + // --------------------------------------------------------- UnitsMismatchError::UnitsMismatchError() @@ -852,6 +925,10 @@ UnitsMismatchError::UnitsMismatchError(const UnitsMismatchError &inst) { } +PyObject *UnitsMismatchError::getPyExceptionType() const { + return PyExc_ArithmeticError; +} + // --------------------------------------------------------- CADKernelError::CADKernelError() diff --git a/src/Base/Exception.h b/src/Base/Exception.h index 11e233aa76f2..6377c2a215bb 100644 --- a/src/Base/Exception.h +++ b/src/Base/Exception.h @@ -79,6 +79,12 @@ #endif +#define FC_THROWM(_exception,_msg) do {\ + std::stringstream ss;\ + ss << _msg;\ + THROWM(_exception,ss.str().c_str());\ +}while(0) + namespace Base { @@ -105,17 +111,24 @@ class BaseExport Exception : public BaseClass inline int getLine() const; inline std::string getFunction() const; inline bool getTranslatable() const; + inline bool getReported() const { return _isReported; } /// setter methods for including debug information /// intended to use via macro for autofilling of debugging information inline void setDebugInformation(const std::string & file, const int line, const std::string & function); inline void setTranslatable(bool translatable); + + inline void setReported(bool reported) { _isReported = reported; } + /// returns a Python dictionary containing the exception data virtual PyObject * getPyObject(void); /// returns sets the exception data from a Python dictionary virtual void setPyObject( PyObject * pydict); + /// returns the corresponding python exception type + virtual PyObject * getPyExceptionType() const {return 0;} + protected: /* sMessage may be: * - a UI compliant string susceptible to being translated and shown to the user in the UI @@ -143,6 +156,7 @@ class BaseExport Exception : public BaseClass */ class BaseExport AbortException : public Exception { + TYPESYSTEM_HEADER(); public: /// Construction AbortException(const char * sMessage); @@ -248,6 +262,8 @@ class BaseExport FileException : public Exception virtual PyObject * getPyObject(void); /// returns sets the exception data from a Python dictionary virtual void setPyObject( PyObject * pydict); + + virtual PyObject * getPyExceptionType() const override; protected: FileInfo file; // necessary for what() legacy behaviour as it returns a buffer that @@ -398,6 +414,7 @@ class BaseExport TypeError : public Exception TypeError(const TypeError &inst); /// Destruction virtual ~TypeError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -415,6 +432,7 @@ class BaseExport ValueError : public Exception ValueError(const ValueError &inst); /// Destruction virtual ~ValueError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -432,6 +450,35 @@ class BaseExport IndexError : public Exception IndexError(const IndexError &inst); /// Destruction virtual ~IndexError() throw() {} + virtual PyObject * getPyExceptionType() const override; +}; + +class BaseExport NameError : public Exception +{ +public: + /// Construction + NameError(); + NameError(const char * sMessage); + NameError(const std::string& sMessage); + /// Construction + NameError(const NameError &inst); + /// Destruction + virtual ~NameError() throw() {} + virtual PyObject * getPyExceptionType() const override; +}; + +class BaseExport ImportError : public Exception +{ +public: + /// Construction + ImportError(); + ImportError(const char * sMessage); + ImportError(const std::string& sMessage); + /// Construction + ImportError(const ImportError &inst); + /// Destruction + virtual ~ImportError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -449,6 +496,7 @@ class BaseExport AttributeError : public Exception AttributeError(const AttributeError &inst); /// Destruction virtual ~AttributeError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -466,6 +514,7 @@ class BaseExport RuntimeError : public Exception RuntimeError(const RuntimeError &inst); /// Destruction virtual ~RuntimeError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -500,10 +549,11 @@ class BaseExport NotImplementedError : public Exception NotImplementedError(const NotImplementedError &inst); /// Destruction virtual ~NotImplementedError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** - * The DivisionByZeroError can be used to indicate a division by zero. + * The ZeroDivisionError can be used to indicate a division by zero. * @author Werner Mayer */ class BaseExport DivisionByZeroError : public Exception @@ -517,10 +567,11 @@ class BaseExport DivisionByZeroError : public Exception DivisionByZeroError(const DivisionByZeroError &inst); /// Destruction virtual ~DivisionByZeroError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** - * The ReferencesError can be used to indicate a reference counter has the wrong value. + * The ReferenceError can be used to indicate a reference counter has the wrong value. * @author Werner Mayer */ class BaseExport ReferencesError : public Exception @@ -534,6 +585,7 @@ class BaseExport ReferencesError : public Exception ReferencesError(const ReferencesError &inst); /// Destruction virtual ~ReferencesError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -586,6 +638,7 @@ class BaseExport UnicodeError : public Exception UnicodeError(const UnicodeError &inst); /// Destruction virtual ~UnicodeError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -603,6 +656,7 @@ class BaseExport OverflowError : public Exception OverflowError(const OverflowError &inst); /// Destruction virtual ~OverflowError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -620,6 +674,7 @@ class BaseExport UnderflowError : public Exception UnderflowError(const UnderflowError &inst); /// Destruction virtual ~UnderflowError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /** @@ -637,6 +692,7 @@ class BaseExport UnitsMismatchError : public Exception UnitsMismatchError(const UnitsMismatchError &inst); /// Destruction virtual ~UnitsMismatchError() throw() {} + virtual PyObject * getPyExceptionType() const override; }; /* The CADKernelError can be used to indicate an exception originating in the CAD Kernel diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp index 6c1369d5cee2..f81a48b17518 100644 --- a/src/Base/Interpreter.cpp +++ b/src/Base/Interpreter.cpp @@ -51,10 +51,21 @@ using namespace Base; #error "Use Python2.5.x or higher" #endif +PyException::PyException(const Py::Object &obj) { + _sErrMsg = obj.as_string(); + // WARNING: we are assumming that python type object will never be + // destroied, so we don't keep reference here to save book-keeping in + // our copy constructor and desctructor + _exceptionType = (PyObject*)obj.ptr()->ob_type; + _errorType = obj.ptr()->ob_type->tp_name; +} PyException::PyException(void) { PP_Fetch_Error_Text(); /* fetch (and clear) exception */ + + setPyObject(PP_PyDict_Object); + std::string prefix = PP_last_error_type; /* exception name text */ // prefix += ": "; std::string error = PP_last_error_info; /* exception data text */ @@ -70,6 +81,16 @@ PyException::PyException(void) _sErrMsg = error; _errorType = prefix; + _exceptionType = PP_last_exception_type; + + if(PP_last_exception_type) { + // WARNING: we are assumming that python type object will never be + // destroied, so we don't keep reference here to save book-keeping in + // our copy constructor and desctructor + Py_DECREF(PP_last_exception_type); + PP_last_exception_type = 0; + + } _stackTrace = PP_last_error_trace; /* exception traceback text */ @@ -86,31 +107,44 @@ PyException::~PyException() throw() void PyException::ThrowException(void) { - PyException myexcp = PyException(); + PyException myexcp; + myexcp.ReportException(); + myexcp.raiseException(); +} +void PyException::raiseException() { PyGILStateLocker locker; + if (PP_PyDict_Object!=NULL) { // delete the Python dict upon destruction of edict Py::Dict edict(PP_PyDict_Object, true); PP_PyDict_Object = 0; - if (!edict.hasKey("sclassname")) - throw myexcp; - - std::string exceptionname = static_cast(Py::String(edict.getItem("sclassname"))); - if (!Base::ExceptionFactory::Instance().CanProduce(exceptionname.c_str())) - throw myexcp; - + std::string exceptionname; + if (_exceptionType == Base::BaseExceptionFreeCADAbort) + edict.setItem("sclassname", + Py::String(typeid(Base::AbortException).name())); + if(_isReported) + edict.setItem("breported", Py::True()); Base::ExceptionFactory::Instance().raiseException(edict.ptr()); } - else - throw myexcp; + + if (_exceptionType == Base::BaseExceptionFreeCADAbort) { + Base::AbortException e(_sErrMsg.c_str()); + e.setReported(_isReported); + throw e; + } + + throw *this; } void PyException::ReportException (void) const { - Base::Console().Error("%s%s: %s\n", - _stackTrace.c_str(), _errorType.c_str(), what()); + if (!_isReported) { + _isReported = true; + Base::Console().Error("%s%s: %s\n", + _stackTrace.c_str(), _errorType.c_str(), what()); + } } // --------------------------------------------------------- diff --git a/src/Base/Interpreter.h b/src/Base/Interpreter.h index f7d57b4d4447..64699dd036c5 100644 --- a/src/Base/Interpreter.h +++ b/src/Base/Interpreter.h @@ -65,7 +65,10 @@ class BaseExport PyException : public Exception public: /// constructor does the whole job PyException(void); + PyException(const Py::Object &obj); ~PyException() throw(); + + void raiseException(); /// this method determines if the original exception /// can be reconstructed or not, if yes throws the reconstructed version @@ -75,11 +78,13 @@ class BaseExport PyException : public Exception /// this function returns the stack trace const std::string &getStackTrace(void) const {return _stackTrace;} const std::string &getErrorType(void) const {return _errorType;} + virtual PyObject *getPyExceptionType(void) const override {return _exceptionType;} void ReportException (void) const; protected: std::string _stackTrace; std::string _errorType; + PyObject *_exceptionType; }; /** diff --git a/src/Base/PyObjectBase.cpp b/src/Base/PyObjectBase.cpp index 2d8e684bd7ef..fb568d0b1bf0 100644 --- a/src/Base/PyObjectBase.cpp +++ b/src/Base/PyObjectBase.cpp @@ -37,6 +37,7 @@ using namespace Base; PyObject* Base::BaseExceptionFreeCADError = 0; +PyObject* Base::BaseExceptionFreeCADAbort = 0; // Constructor PyObjectBase::PyObjectBase(void* p,PyTypeObject *T) diff --git a/src/Base/PyObjectBase.h b/src/Base/PyObjectBase.h index eef000e8c3d6..94cfb7b7d4ed 100644 --- a/src/Base/PyObjectBase.h +++ b/src/Base/PyObjectBase.h @@ -147,7 +147,11 @@ inline void Assert(int expr, char *msg) // C++ assert /// return with no return value if nothing happens #define Py_Return return Py_INCREF(Py_None), Py_None /// returns an error -#define Py_Error(E, M) {PyErr_SetString(E, M); return NULL;} +#define Py_Error(E, M) _Py_Error(return(NULL),E,M) +#define _Py_Error(R, E, M) {PyErr_SetString(E, M); R;} +/// returns an error +#define Py_ErrorObj(E, O) _Py_ErrorObj(return(NULL),E,O) +#define _Py_ErrorObj(R, E, O) {PyErr_SetObject(E, O); R;} /// checks on a condition and returns an error on failure #define Py_Try(F) {if (!(F)) return NULL;} /// assert which returns with an error on failure @@ -411,6 +415,7 @@ BaseExport extern PyObject* BaseExceptionFreeCADError; #define PY_FCERROR (Base::BaseExceptionFreeCADError ? \ BaseExceptionFreeCADError : PyExc_RuntimeError) +BaseExport extern PyObject* BaseExceptionFreeCADAbort; /** Exception handling for python callback functions * Is a convenience macro to manage the exception handling of python callback @@ -451,16 +456,25 @@ BaseExport extern PyObject* BaseExceptionFreeCADError; */ #define PY_TRY try -#ifndef DONT_CATCH_CXX_EXCEPTIONS -/// see docu of PY_TRY -# define PY_CATCH catch(Base::Exception &e) \ +#define __PY_CATCH(R) \ + catch(Base::AbortException &e) \ + { \ + e.ReportException(); \ + _Py_ErrorObj(R,Base::BaseExceptionFreeCADAbort,e.getPyObject());\ + } \ + catch(Base::Exception &e) \ { \ - std::string str; \ - str += "FreeCAD exception thrown ("; \ - str += e.what(); \ - str += ")"; \ e.ReportException(); \ - Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \ + auto pye = e.getPyExceptionType(); \ + if(!pye) { \ + pye = Base::BaseExceptionFreeCADError; \ + std::string str; \ + str += "FreeCAD exception thrown ("; \ + str += e.what(); \ + str += ")"; \ + e.setMessage(str); \ + } \ + _Py_ErrorObj(R,pye,e.getPyObject()); \ } \ catch(std::exception &e) \ { \ @@ -469,52 +483,33 @@ BaseExport extern PyObject* BaseExceptionFreeCADError; str += e.what(); \ str += ")"; \ Base::Console().Error(str.c_str()); \ - Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \ + _Py_Error(R,Base::BaseExceptionFreeCADError,str.c_str()); \ } \ catch(const Py::Exception&) \ { \ - return NULL; \ + R; \ } \ catch(const char *e) \ { \ - Py_Error(Base::BaseExceptionFreeCADError,e); \ + _Py_Error(R,Base::BaseExceptionFreeCADError,e); \ } \ + +#ifndef DONT_CATCH_CXX_EXCEPTIONS +/// see docu of PY_TRY +# define _PY_CATCH(R) \ + __PY_CATCH(R) \ catch(...) \ { \ - Py_Error(Base::BaseExceptionFreeCADError,"Unknown C++ exception"); \ + _Py_Error(R,Base::BaseExceptionFreeCADError,"Unknown C++ exception"); \ } #else /// see docu of PY_TRY -# define PY_CATCH catch(Base::Exception &e) \ - { \ - std::string str; \ - str += "FreeCAD exception thrown ("; \ - str += e.what(); \ - str += ")"; \ - e.ReportException(); \ - Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \ - } \ - catch(std::exception &e) \ - { \ - std::string str; \ - str += "STL exception thrown ("; \ - str += e.what(); \ - str += ")"; \ - Base::Console().Error(str.c_str()); \ - Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \ - } \ - catch(const Py::Exception&) \ - { \ - return NULL; \ - } \ - catch(const char *e) \ - { \ - Py_Error(Base::BaseExceptionFreeCADError,e); \ - } - +# define _PY_CATCH(R) __PY_CATCH(R) #endif // DONT_CATCH_CXX_EXCEPTIONS +#define PY_CATCH _PY_CATCH(return(NULL)) + /** Python helper class * This class encapsulate the Decoding of UTF8 to a python object. * Including exception handling. diff --git a/src/Base/PyTools.c b/src/Base/PyTools.c index 7a6a705a58e1..1ec7d90b1c29 100644 --- a/src/Base/PyTools.c +++ b/src/Base/PyTools.c @@ -16,6 +16,7 @@ is provided on an as is basis, without warranties of any kind. #include #include #include +#include #if PY_VERSION_HEX <= 0x02050000 #error "Use Python2.5.x or higher" @@ -219,6 +220,7 @@ char PP_last_error_trace[MAX]; /* exception traceback text */ PyObject *PP_last_traceback = NULL; /* saved exception traceback object */ PyObject *PP_PyDict_Object = NULL; /* saved exception dictionary object */ +PyObject *PP_last_exception_type = NULL; /* saved exception python type */ void PP_Fetch_Error_Text() @@ -254,7 +256,8 @@ void PP_Fetch_Error_Text() } else { - strcpy(PP_last_error_type, ""); + /* strcpy(PP_last_error_type, ""); */ + PP_last_error_type[0] = '\0'; } Py_XDECREF(pystring); @@ -318,11 +321,32 @@ void PP_Fetch_Error_Text() PP_last_error_trace[MAX-1] = '\0'; free(tempstr); /* it's a strdup */ } - else - strcpy(PP_last_error_trace, ""); + else { + PyFrameObject* frame = PyEval_GetFrame(); + if(!frame) + return; + int line = PyFrame_GetLineNumber(frame); +#if PY_MAJOR_VERSION >= 3 + const char *file = PyUnicode_AsUTF8(frame->f_code->co_filename); +#else + const char *file = PyString_AsString(frame->f_code->co_filename); +#endif +#ifdef FC_OS_WIN32 + const char *_f = strstr(file, "\\src\\"); +#else + const char *_f = strstr(file, "/src/"); +#endif + /* strcpy(PP_last_error_trace, ""); */ + snprintf(PP_last_error_trace,sizeof(PP_last_error_trace),"%s(%d)",(_f?_f+5:file),line); + } Py_XDECREF(pystring); - + Py_XDECREF(PP_last_exception_type); + if(errobj) { + PP_last_exception_type = errobj; + Py_INCREF(errobj); + }else + PP_last_exception_type = 0; Py_XDECREF(errobj); Py_XDECREF(errdata); /* this function owns all 3 objects */ Py_XDECREF(PP_last_traceback); /* they've been NULL'd out in Python */ diff --git a/src/Base/PyTools.h b/src/Base/PyTools.h index 716af426d22c..bc1d4c43bc74 100644 --- a/src/Base/PyTools.h +++ b/src/Base/PyTools.h @@ -182,6 +182,7 @@ extern char PP_last_error_trace[]; /* exception traceback text */ extern PyObject *PP_PyDict_Object; /* saved PyDict object */ extern PyObject *PP_last_traceback; /* saved exception traceback object */ +extern PyObject *PP_last_exception_type; /* saved exception type */ #ifdef __cplusplus