Base: improve exception
For better FC and Python exception mapping.
This commit is contained in:
@@ -194,6 +194,7 @@ Base::ConsoleObserverFile *Application::_pConsoleObserverFile =0;
|
||||
|
||||
AppExport std::map<std::string,std::string> Application::mConfig;
|
||||
BaseExport extern PyObject* Base::BaseExceptionFreeCADError;
|
||||
BaseExport extern PyObject* Base::BaseExceptionFreeCADAbort;
|
||||
|
||||
//**************************************************************************
|
||||
// Construction and destruction
|
||||
@@ -314,6 +315,10 @@ Application::Application(std::map<std::string,std::string> &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<Base::TypeError>;
|
||||
new ExceptionProducer<Base::ValueError>;
|
||||
new ExceptionProducer<Base::IndexError>;
|
||||
new ExceptionProducer<Base::NameError>;
|
||||
new ExceptionProducer<Base::ImportError>;
|
||||
new ExceptionProducer<Base::AttributeError>;
|
||||
new ExceptionProducer<Base::RuntimeError>;
|
||||
new ExceptionProducer<Base::BadGraphError>;
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "Console.h"
|
||||
#include <CXX/Objects.hxx>
|
||||
|
||||
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()
|
||||
|
||||
@@ -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 @@ public:
|
||||
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 @@ protected:
|
||||
*/
|
||||
class BaseExport AbortException : public Exception
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
/// Construction
|
||||
AbortException(const char * sMessage);
|
||||
@@ -248,6 +262,8 @@ public:
|
||||
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 @@ public:
|
||||
TypeError(const TypeError &inst);
|
||||
/// Destruction
|
||||
virtual ~TypeError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -415,6 +432,7 @@ public:
|
||||
ValueError(const ValueError &inst);
|
||||
/// Destruction
|
||||
virtual ~ValueError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -432,6 +450,35 @@ public:
|
||||
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 @@ public:
|
||||
AttributeError(const AttributeError &inst);
|
||||
/// Destruction
|
||||
virtual ~AttributeError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -466,6 +514,7 @@ public:
|
||||
RuntimeError(const RuntimeError &inst);
|
||||
/// Destruction
|
||||
virtual ~RuntimeError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -500,10 +549,11 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
ReferencesError(const ReferencesError &inst);
|
||||
/// Destruction
|
||||
virtual ~ReferencesError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -586,6 +638,7 @@ public:
|
||||
UnicodeError(const UnicodeError &inst);
|
||||
/// Destruction
|
||||
virtual ~UnicodeError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -603,6 +656,7 @@ public:
|
||||
OverflowError(const OverflowError &inst);
|
||||
/// Destruction
|
||||
virtual ~OverflowError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -620,6 +674,7 @@ public:
|
||||
UnderflowError(const UnderflowError &inst);
|
||||
/// Destruction
|
||||
virtual ~UnderflowError() throw() {}
|
||||
virtual PyObject * getPyExceptionType() const override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -637,6 +692,7 @@ public:
|
||||
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
|
||||
|
||||
@@ -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<std::string>(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());
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
@@ -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 @@ public:
|
||||
/// 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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
using namespace Base;
|
||||
|
||||
PyObject* Base::BaseExceptionFreeCADError = 0;
|
||||
PyObject* Base::BaseExceptionFreeCADAbort = 0;
|
||||
|
||||
// Constructor
|
||||
PyObjectBase::PyObjectBase(void* p,PyTypeObject *T)
|
||||
|
||||
@@ -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) \
|
||||
{ \
|
||||
std::string str; \
|
||||
str += "FreeCAD exception thrown ("; \
|
||||
str += e.what(); \
|
||||
str += ")"; \
|
||||
e.ReportException(); \
|
||||
Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \
|
||||
_Py_ErrorObj(R,Base::BaseExceptionFreeCADAbort,e.getPyObject());\
|
||||
} \
|
||||
catch(Base::Exception &e) \
|
||||
{ \
|
||||
e.ReportException(); \
|
||||
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.
|
||||
|
||||
@@ -16,6 +16,7 @@ is provided on an as is basis, without warranties of any kind.
|
||||
#include <assert.h>
|
||||
#include <compile.h>
|
||||
#include <eval.h>
|
||||
#include <frameobject.h>
|
||||
|
||||
#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, "<unknown exception type>");
|
||||
/* strcpy(PP_last_error_type, "<unknown exception 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, "<unknown exception traceback>");
|
||||
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, "<unknown exception traceback>"); */
|
||||
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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user