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 "tlTimer.h"
|
||||||
#include "tlFileUtils.h"
|
#include "tlFileUtils.h"
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
|
#include "tlInternational.h"
|
||||||
|
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
# include <QCoreApplication>
|
# include <QCoreApplication>
|
||||||
|
|
@ -51,6 +52,38 @@
|
||||||
namespace pya
|
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 tl::ScriptError
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PythonError (const char *msg, const char *cls, const std::vector <tl::BacktraceElement> &backtrace)
|
PythonError (const char *msg, const char *cls, const std::vector <tl::BacktraceElement> &backtrace);
|
||||||
: tl::ScriptError (msg, cls, 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)
|
private:
|
||||||
: tl::ScriptError (d)
|
int m_index;
|
||||||
{ }
|
std::string m_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PythonModule;
|
class PythonModule;
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ long python2c_func<long>::operator() (PyObject *rval)
|
||||||
} else if (PyFloat_Check (rval)) {
|
} else if (PyFloat_Check (rval)) {
|
||||||
return (long) (PyFloat_AsDouble (rval));
|
return (long) (PyFloat_AsDouble (rval));
|
||||||
} else {
|
} 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)) {
|
} else if (PyFloat_Check (rval)) {
|
||||||
return char (PyFloat_AsDouble (rval));
|
return char (PyFloat_AsDouble (rval));
|
||||||
} else {
|
} 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)) {
|
} else if (PyFloat_Check (rval)) {
|
||||||
return (unsigned long) (PyFloat_AsDouble (rval));
|
return (unsigned long) (PyFloat_AsDouble (rval));
|
||||||
} else {
|
} 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)) {
|
} else if (PyFloat_Check (rval)) {
|
||||||
return (long long) (PyFloat_AsDouble (rval));
|
return (long long) (PyFloat_AsDouble (rval));
|
||||||
} else {
|
} 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)) {
|
} else if (PyFloat_Check (rval)) {
|
||||||
return (unsigned long long) (PyFloat_AsDouble (rval));
|
return (unsigned long long) (PyFloat_AsDouble (rval));
|
||||||
} else {
|
} 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)) {
|
} else if (PyFloat_Check (rval)) {
|
||||||
return PyFloat_AsDouble (rval);
|
return PyFloat_AsDouble (rval);
|
||||||
} else {
|
} 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
|
#endif
|
||||||
|
|
@ -163,7 +163,7 @@ double python2c_func<double>::operator() (PyObject *rval)
|
||||||
} else if (PyFloat_Check (rval)) {
|
} else if (PyFloat_Check (rval)) {
|
||||||
return PyFloat_AsDouble (rval);
|
return PyFloat_AsDouble (rval);
|
||||||
} else {
|
} 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)) {
|
} else if (PyByteArray_Check (rval)) {
|
||||||
return std::string (PyByteArray_AsString (rval), PyByteArray_Size (rval));
|
return std::string (PyByteArray_AsString (rval), PyByteArray_Size (rval));
|
||||||
} else {
|
} 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);
|
Py_ssize_t sz = PyByteArray_Size (rval);
|
||||||
return std::vector<char> (cp, cp + sz);
|
return std::vector<char> (cp, cp + sz);
|
||||||
} else {
|
} 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)) {
|
} else if (PyByteArray_Check (rval)) {
|
||||||
return QByteArray (PyByteArray_AsString (rval), PyByteArray_Size (rval));
|
return QByteArray (PyByteArray_AsString (rval), PyByteArray_Size (rval));
|
||||||
} else {
|
} 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 *
|
static PyObject *
|
||||||
method_adaptor (int mid, PyObject *self, PyObject *args)
|
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")));
|
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;
|
void *obj = 0;
|
||||||
if (p) {
|
if (p) {
|
||||||
// Hint: this potentially instantiates the object
|
// 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 retlist (meth->retsize ());
|
||||||
gsi::SerialArgs arglist (meth->argsize ());
|
gsi::SerialArgs arglist (meth->argsize ());
|
||||||
|
|
||||||
try {
|
push_args (arglist, meth, args, heap);
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
meth->call (obj, arglist, retlist);
|
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 retlist (meth->retsize ());
|
||||||
gsi::SerialArgs arglist (meth->argsize ());
|
gsi::SerialArgs arglist (meth->argsize ());
|
||||||
|
|
||||||
try {
|
push_args (arglist, meth, args, heap);
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
meth->call (0, arglist, retlist);
|
meth->call (0, arglist, retlist);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue