mirror of https://github.com/KLayout/klayout.git
Express argument details in Python call errors
This commit is contained in:
parent
82fe920ac9
commit
7d078ed041
|
|
@ -38,6 +38,7 @@
|
|||
#include "tlTimer.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlString.h"
|
||||
#include "tlInternational.h"
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
# include <QCoreApplication>
|
||||
|
|
@ -51,6 +52,38 @@
|
|||
namespace pya
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// PythonError implementation
|
||||
|
||||
PythonError::PythonError (const char *msg, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
|
||||
: tl::ScriptError (msg, cls, backtrace)
|
||||
{ }
|
||||
|
||||
PythonError::PythonError (const char *msg, const char *sourcefile, int line, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
|
||||
: tl::ScriptError (msg, sourcefile, line, cls, backtrace)
|
||||
{ }
|
||||
|
||||
PythonError::PythonError (const PythonError &d)
|
||||
: tl::ScriptError (d)
|
||||
{ }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// PythonArgumentError implementation
|
||||
|
||||
PythonArgumentError::PythonArgumentError (const tl::Exception &ex, int index, const std::string &name)
|
||||
: tl::Exception (ex.msg ()), m_index (index), m_name (name)
|
||||
{ }
|
||||
|
||||
std::string
|
||||
PythonArgumentError::msg () const
|
||||
{
|
||||
if (! m_name.empty ()) {
|
||||
return tl::sprintf (tl::to_string (tr ("%s for argument #%d ('%s')")), tl::Exception::msg (), m_index + 1, m_name);
|
||||
} else {
|
||||
return tl::sprintf (tl::to_string (tr ("%s for argument #%d")), tl::Exception::msg (), m_index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -77,17 +77,24 @@ class PYA_PUBLIC PythonError
|
|||
: public tl::ScriptError
|
||||
{
|
||||
public:
|
||||
PythonError (const char *msg, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
|
||||
: tl::ScriptError (msg, cls, backtrace)
|
||||
{ }
|
||||
PythonError (const char *msg, const char *cls, const std::vector <tl::BacktraceElement> &backtrace);
|
||||
PythonError (const char *msg, const char *sourcefile, int line, const char *cls, const std::vector <tl::BacktraceElement> &backtrace);
|
||||
PythonError (const PythonError &d);
|
||||
};
|
||||
|
||||
PythonError (const char *msg, const char *sourcefile, int line, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
|
||||
: tl::ScriptError (msg, sourcefile, line, cls, backtrace)
|
||||
{ }
|
||||
/**
|
||||
* @brief A class encapsulating an argument error
|
||||
*/
|
||||
class PYA_PUBLIC PythonArgumentError
|
||||
: public tl::Exception
|
||||
{
|
||||
public:
|
||||
PythonArgumentError (const tl::Exception &ex, int index, const std::string &name);
|
||||
virtual std::string msg () const;
|
||||
|
||||
PythonError (const PythonError &d)
|
||||
: tl::ScriptError (d)
|
||||
{ }
|
||||
private:
|
||||
int m_index;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
class PythonModule;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ long python2c_func<long>::operator() (PyObject *rval)
|
|||
} else if (PyFloat_Check (rval)) {
|
||||
return (long) (PyFloat_AsDouble (rval));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to an integer")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ char python2c_func<char>::operator() (PyObject *rval)
|
|||
} else if (PyFloat_Check (rval)) {
|
||||
return char (PyFloat_AsDouble (rval));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to a character")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a character")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ unsigned long python2c_func<unsigned long>::operator() (PyObject *rval)
|
|||
} else if (PyFloat_Check (rval)) {
|
||||
return (unsigned long) (PyFloat_AsDouble (rval));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to an integer")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ long long python2c_func<long long>::operator() (PyObject *rval)
|
|||
} else if (PyFloat_Check (rval)) {
|
||||
return (long long) (PyFloat_AsDouble (rval));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to an integer")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ unsigned long long python2c_func<unsigned long long>::operator() (PyObject *rval
|
|||
} else if (PyFloat_Check (rval)) {
|
||||
return (unsigned long long) (PyFloat_AsDouble (rval));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to an integer")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ __int128 python2c_func<__int128>::operator() (PyObject *rval)
|
|||
} else if (PyFloat_Check (rval)) {
|
||||
return PyFloat_AsDouble (rval);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to an integer")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -163,7 +163,7 @@ double python2c_func<double>::operator() (PyObject *rval)
|
|||
} else if (PyFloat_Check (rval)) {
|
||||
return PyFloat_AsDouble (rval);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to a floating-point value")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a floating-point value")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ std::string python2c_func<std::string>::operator() (PyObject *rval)
|
|||
} else if (PyByteArray_Check (rval)) {
|
||||
return std::string (PyByteArray_AsString (rval), PyByteArray_Size (rval));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to a string")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a string")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ std::vector<char> python2c_func<std::vector<char> >::operator() (PyObject *rval)
|
|||
Py_ssize_t sz = PyByteArray_Size (rval);
|
||||
return std::vector<char> (cp, cp + sz);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to a byte array")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a byte array")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ QByteArray python2c_func<QByteArray>::operator() (PyObject *rval)
|
|||
} else if (PyByteArray_Check (rval)) {
|
||||
return QByteArray (PyByteArray_AsString (rval), PyByteArray_Size (rval));
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to a byte array")));
|
||||
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a byte array")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1175,6 +1175,42 @@ special_method_impl (gsi::MethodBase::special_method_type smt, PyObject *self, P
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, PyObject *args, tl::Heap &heap)
|
||||
{
|
||||
int i = 0;
|
||||
int argc = args == NULL ? 0 : int (PyTuple_Size (args));
|
||||
|
||||
try {
|
||||
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); i < argc && a != meth->end_arguments (); ++a, ++i) {
|
||||
push_arg (*a, arglist, PyTuple_GetItem (args, i), heap);
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
// In case of an error upon write, pop the arguments to clean them up.
|
||||
// Without this, there is a risk to keep dead objects on the stack.
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && arglist; ++a) {
|
||||
pop_arg (*a, arglist, 0, heap);
|
||||
}
|
||||
|
||||
const gsi::ArgSpecBase *arg_spec = meth->begin_arguments () [i].spec ();
|
||||
throw PythonArgumentError (ex, i, arg_spec ? arg_spec->name () : std::string ());
|
||||
|
||||
} catch (...) {
|
||||
|
||||
// In case of an error upon write, pop the arguments to clean them up.
|
||||
// Without this, there is a risk to keep dead objects on the stack.
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && arglist; ++a) {
|
||||
pop_arg (*a, arglist, 0, heap);
|
||||
}
|
||||
|
||||
throw;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_adaptor (int mid, PyObject *self, PyObject *args)
|
||||
{
|
||||
|
|
@ -1203,8 +1239,6 @@ method_adaptor (int mid, PyObject *self, PyObject *args)
|
|||
throw tl::Exception (tl::to_string (tr ("Cannot call non-const method on a const reference")));
|
||||
}
|
||||
|
||||
int argc = args == NULL ? 0 : int (PyTuple_Size (args));
|
||||
|
||||
void *obj = 0;
|
||||
if (p) {
|
||||
// Hint: this potentially instantiates the object
|
||||
|
|
@ -1214,24 +1248,7 @@ method_adaptor (int mid, PyObject *self, PyObject *args)
|
|||
gsi::SerialArgs retlist (meth->retsize ());
|
||||
gsi::SerialArgs arglist (meth->argsize ());
|
||||
|
||||
try {
|
||||
|
||||
int i = 0;
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); i < argc && a != meth->end_arguments (); ++a, ++i) {
|
||||
push_arg (*a, arglist, PyTuple_GetItem (args, i), heap);
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
|
||||
// In case of an error upon write, pop the arguments to clean them up.
|
||||
// Without this, there is a risk to keep dead objects on the stack.
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && arglist; ++a) {
|
||||
pop_arg (*a, arglist, 0, heap);
|
||||
}
|
||||
|
||||
throw;
|
||||
|
||||
}
|
||||
push_args (arglist, meth, args, heap);
|
||||
|
||||
meth->call (obj, arglist, retlist);
|
||||
|
||||
|
|
@ -1764,25 +1781,7 @@ method_init_adaptor (int mid, PyObject *self, PyObject *args)
|
|||
gsi::SerialArgs retlist (meth->retsize ());
|
||||
gsi::SerialArgs arglist (meth->argsize ());
|
||||
|
||||
try {
|
||||
|
||||
int i = 0;
|
||||
int argc = args == NULL ? 0 : int (PyTuple_Size (args));
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); i < argc && a != meth->end_arguments (); ++a, ++i) {
|
||||
push_arg (*a, arglist, PyTuple_GetItem (args, i), heap);
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
|
||||
// In case of an error upon write, pop the arguments to clean them up.
|
||||
// Without this, there is a risk to keep dead objects on the stack.
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && arglist; ++a) {
|
||||
pop_arg (*a, arglist, 0, heap);
|
||||
}
|
||||
|
||||
throw;
|
||||
|
||||
}
|
||||
push_args (arglist, meth, args, heap);
|
||||
|
||||
meth->call (0, arglist, retlist);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue