Correct docs and examples to call SWIG_fail after setting a Python error

Although 'return NULL' works, it may miss out on some cleanup and NULL
is the wrong value to return in generated code for overloaded functions.
This commit is contained in:
William S Fulton 2016-10-21 08:02:12 +01:00
commit 129ef8ea8f
7 changed files with 74 additions and 66 deletions

View file

@ -3717,7 +3717,7 @@ or a NULL pointer perhaps). Here is a simple example of how you might handle th
$action
if (!result) {
PyErr_SetString(PyExc_MemoryError,"Not enough memory");
return NULL;
SWIG_fail;
}
}
void *malloc(size_t nbytes);
@ -3749,7 +3749,7 @@ that. For example:
$action
if (err_occurred()) {
PyErr_SetString(PyExc_RuntimeError, err_message());
return NULL;
SWIG_fail;
}
}
</pre>
@ -3770,7 +3770,7 @@ C++ exceptions are also easy to handle. For example, you can write code like th
$action
} catch (std::out_of_range &amp;e) {
PyErr_SetString(PyExc_IndexError, const_cast&lt;char*&gt;(e.what()));
return NULL;
SWIG_fail;
}
}
@ -3784,7 +3784,8 @@ public:
<p>
When raising a Python exception from C, use the <tt>PyErr_SetString()</tt>
function as shown above. The following exception types can be used as the first argument.
function as shown above followed by <tt>SWIG_fail</tt>.
The following exception types can be used as the first argument.
</p>
<div class="code">
@ -3818,6 +3819,13 @@ PyExc_ZeroDivisionError
</pre>
</div>
<p>
<tt>SWIG_fail</tt> is a C macro which when called within the context of SWIG wrapper function,
will jump to the error handler code. This will call any cleanup code (freeing any temp variables)
and then return from the wrapper function so that the Python interpreter can raise the Python exception.
This macro should always be called after setting a Python error in code snippets, such as typemaps and <tt>%exception</tt>, that are ultimately generated into the wrapper function.
</p>
<p>
The language-independent <tt>exception.i</tt> library file can also be used
to raise exceptions. See the <a href="Library.html#Library">SWIG Library</a> chapter.
@ -4417,7 +4425,7 @@ You can refine this by supplying an optional parameter name. For example:
$1 = (int) PyLong_AsLong($input);
if ($1 &lt; 0) {
PyErr_SetString(PyExc_ValueError,"Expected a nonnegative value.");
return NULL;
SWIG_fail;
}
}
%inline %{
@ -4750,18 +4758,18 @@ object to be used as a <tt>char **</tt> object.
$1 = (char **) malloc((size+1)*sizeof(char *));
for (i = 0; i &lt; size; i++) {
PyObject *o = PyList_GetItem($input,i);
if (PyString_Check(o))
if (PyString_Check(o)) {
$1[i] = PyString_AsString(PyList_GetItem($input,i));
else {
PyErr_SetString(PyExc_TypeError,"list must contain strings");
} else {
free($1);
return NULL;
PyErr_SetString(PyExc_TypeError,"list must contain strings");
SWIG_fail;
}
}
$1[i] = 0;
} else {
PyErr_SetString(PyExc_TypeError,"not a list");
return NULL;
SWIG_fail;
}
}
@ -4849,18 +4857,18 @@ previous example:
$2 = (char **) malloc(($1+1)*sizeof(char *));
for (i = 0; i &lt; $1; i++) {
PyObject *o = PyList_GetItem($input,i);
if (PyString_Check(o))
if (PyString_Check(o)) {
$2[i] = PyString_AsString(PyList_GetItem($input,i));
else {
PyErr_SetString(PyExc_TypeError,"list must contain strings");
} else {
free($2);
return NULL;
PyErr_SetString(PyExc_TypeError,"list must contain strings");
SWIG_fail;
}
}
$2[i] = 0;
} else {
PyErr_SetString(PyExc_TypeError,"not a list");
return NULL;
SWIG_fail;
}
}
@ -5038,12 +5046,12 @@ This too, can be handled used typemaps as follows :
if (PyTuple_Check($input)) {
if (!PyArg_ParseTuple($input,"dddd",temp,temp+1,temp+2,temp+3)) {
PyErr_SetString(PyExc_TypeError,"tuple must have 4 elements");
return NULL;
SWIG_fail;
}
$1 = &amp;temp[0];
} else {
PyErr_SetString(PyExc_TypeError,"expected a tuple.");
return NULL;
SWIG_fail;
}
}
@ -5078,18 +5086,18 @@ arrays of different sizes. To do this, you might write a typemap as follows:
int i;
if (!PySequence_Check($input)) {
PyErr_SetString(PyExc_TypeError,"Expecting a sequence");
return NULL;
SWIG_fail;
}
if (PyObject_Length($input) != $1_dim0) {
PyErr_SetString(PyExc_ValueError,"Expecting a sequence with $1_dim0 elements");
return NULL;
SWIG_fail;
}
for (i =0; i &lt; $1_dim0; i++) {
PyObject *o = PySequence_GetItem($input,i);
if (!PyFloat_Check(o)) {
Py_XDECREF(o);
PyErr_SetString(PyExc_ValueError,"Expecting a sequence of floats");
return NULL;
SWIG_fail;
}
temp[i] = PyFloat_AsDouble(o);
Py_DECREF(o);
@ -5146,7 +5154,7 @@ static int convert_darray(PyObject *input, double *ptr, int size) {
%typemap(in) double [ANY](double temp[$1_dim0]) {
if (!convert_darray($input,temp,$1_dim0)) {
return NULL;
SWIG_fail;
}
$1 = &amp;temp[0];
}

View file

@ -373,11 +373,11 @@ example, you could write a typemap like this:
<div class="code">
<pre>
%typemap(in) <b>double nonnegative</b> {
$1 = PyFloat_AsDouble($input);
if ($1 &lt; 0) {
PyErr_SetString(PyExc_ValueError,"argument must be nonnegative.");
return NULL;
}
$1 = PyFloat_AsDouble($input);
if ($1 &lt; 0) {
PyErr_SetString(PyExc_ValueError,"argument must be nonnegative.");
SWIG_fail;
}
}
...
@ -2964,11 +2964,11 @@ similar to this:
int i;
if (!PySequence_Check($input)) {
PyErr_SetString(PyExc_ValueError,"Expected a sequence");
return NULL;
SWIG_fail;
}
if (PySequence_Length($input) != 4) {
PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected 4 elements");
return NULL;
SWIG_fail;
}
for (i = 0; i &lt; 4; i++) {
PyObject *o = PySequence_GetItem($input,i);
@ -2976,7 +2976,7 @@ similar to this:
temp[i] = (float) PyFloat_AsDouble(o);
} else {
PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");
return NULL;
SWIG_fail;
}
}
$1 = temp;
@ -3009,11 +3009,11 @@ If you wanted to generalize the typemap to apply to arrays of all dimensions you
int i;
if (!PySequence_Check($input)) {
PyErr_SetString(PyExc_ValueError,"Expected a sequence");
return NULL;
SWIG_fail;
}
if (PySequence_Length($input) != $1_dim0) {
PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
return NULL;
SWIG_fail;
}
for (i = 0; i &lt; $1_dim0; i++) {
PyObject *o = PySequence_GetItem($input,i);
@ -3021,7 +3021,7 @@ If you wanted to generalize the typemap to apply to arrays of all dimensions you
temp[i] = (float) PyFloat_AsDouble(o);
} else {
PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");
return NULL;
SWIG_fail;
}
}
$1 = temp;
@ -3053,11 +3053,11 @@ as shown. To work with heap allocated data, the following technique can be use
int i;
if (!PySequence_Check($input)) {
PyErr_SetString(PyExc_ValueError,"Expected a sequence");
return NULL;
SWIG_fail;
}
if (PySequence_Length($input) != $1_dim0) {
PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
return NULL;
SWIG_fail;
}
$1 = (float *) malloc($1_dim0*sizeof(float));
for (i = 0; i &lt; $1_dim0; i++) {
@ -3065,9 +3065,9 @@ as shown. To work with heap allocated data, the following technique can be use
if (PyNumber_Check(o)) {
$1[i] = (float) PyFloat_AsDouble(o);
} else {
PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");
free($1);
return NULL;
PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");
SWIG_fail;
}
}
}
@ -3229,7 +3229,7 @@ pointers. For example:</p>
%typemap(check) Vector * {
if ($1 == 0) {
PyErr_SetString(PyExc_TypeError,"NULL Pointer not allowed");
return NULL;
SWIG_fail;
}
}
@ -3508,7 +3508,7 @@ maps perform the conversion described for the above example:
int i;
if (!PyList_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting a list");
return NULL;
SWIG_fail;
}
$1 = PyList_Size($input);
$2 = (char **) malloc(($1+1)*sizeof(char *));
@ -3517,7 +3517,7 @@ maps perform the conversion described for the above example:
if (!PyString_Check(s)) {
free($2);
PyErr_SetString(PyExc_ValueError, "List items must be strings");
return NULL;
SWIG_fail;
}
$2[i] = PyString_AsString(s);
}
@ -3633,7 +3633,7 @@ might write typemaps like this:
%typemap(in) (void *wbuffer, size_t len) {
if (!PyString_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting a string");
return NULL;
SWIG_fail;
}
$1 = (void *) PyString_AsString($input);
$2 = PyString_Size($input);
@ -3643,12 +3643,12 @@ might write typemaps like this:
%typemap(in) (void *rbuffer, size_t len) {
if (!PyInt_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting an integer");
return NULL;
SWIG_fail;
}
$2 = PyInt_AsLong($input);
if ($2 &lt; 0) {
PyErr_SetString(PyExc_ValueError, "Positive integer expected");
return NULL;
SWIG_fail;
}
$1 = (void *) malloc($2);
}

View file

@ -517,7 +517,7 @@ like this:
argc = PyTuple_Size(varargs);
if (argc &gt; 10) {
PyErr_SetString(PyExc_ValueError, "Too many arguments");
return NULL;
SWIG_fail;
}
for (i = 0; i &lt; argc; i++) {
PyObject *pyobj = PyTuple_GetItem(varargs, i);
@ -526,7 +526,7 @@ like this:
PyObject *pystr;
if (!PyUnicode_Check(pyobj)) {
PyErr_SetString(PyExc_ValueError, "Expected a string");
return NULL;
SWIG_fail;
}
pystr = PyUnicode_AsUTF8String(pyobj);
str = strdup(PyBytes_AsString(pystr));
@ -534,7 +534,7 @@ like this:
%#else
if (!PyString_Check(pyobj)) {
PyErr_SetString(PyExc_ValueError, "Expected a string");
return NULL;
SWIG_fail;
}
str = PyString_AsString(pyobj);
%#endif
@ -635,9 +635,9 @@ example. For example:
for (i = 0; i &lt; argc; i++) {
PyObject *o = PyTuple_GetItem(varargs,i);
if (!PyString_Check(o)) {
PyErr_SetString(PyExc_ValueError,"Expected a string");
free(argv);
return NULL;
PyErr_SetString(PyExc_ValueError,"Expected a string");
SWIG_fail;
}
argv[i] = PyString_AsString(o);
}
@ -676,11 +676,11 @@ example. For example:
&amp;ffi_type_uint, types) == FFI_OK) {
ffi_call(&amp;cif, (void (*)()) execlp, &amp;result, values);
} else {
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
free(types);
free(values);
free(arg3);
return NULL;
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
SWIG_fail;
}
free(types);
free(values);
@ -744,8 +744,8 @@ As a more extreme example of libffi, here is some code that attempts to wrap <tt
argv[i].type = VT_POINTER;
argv[i].val.pvalue = (void *) PyString_AsString(o);
} else {
PyErr_SetString(PyExc_ValueError,"Unsupported argument type");
free(argv);
PyErr_SetString(PyExc_ValueError,"Unsupported argument type");
return NULL;
}
}
@ -793,11 +793,11 @@ As a more extreme example of libffi, here is some code that attempts to wrap <tt
&amp;ffi_type_uint, types) == FFI_OK) {
ffi_call(&amp;cif, (void (*)()) printf, &amp;result, values);
} else {
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
free(types);
free(values);
free(args);
return NULL;
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
SWIG_fail;
}
free(types);
free(values);

View file

@ -20,7 +20,7 @@
PyObject *o = PyTuple_GetItem(varargs,i);
if (!PyString_Check(o)) {
PyErr_SetString(PyExc_ValueError,"Expected a string");
return NULL;
SWIG_fail;
}
argv[i] = PyString_AsString(o);
}
@ -58,11 +58,11 @@
&ffi_type_uint, types) == FFI_OK) {
ffi_call(&cif, (void (*)()) execlp, &result, values);
} else {
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
free(types);
free(values);
free(arg3);
return NULL;
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
SWIG_fail;
}
free(types);
free(values);
@ -107,9 +107,9 @@ int execlp(const char *path, const char *arg1, ...);
argv[i].type = VT_POINTER;
argv[i].val.pvalue = (void *) PyString_AsString(o);
} else {
PyErr_SetString(PyExc_ValueError,"Unsupported argument type");
free(argv);
return NULL;
PyErr_SetString(PyExc_ValueError,"Unsupported argument type");
SWIG_fail;
}
}
@ -157,11 +157,11 @@ int execlp(const char *path, const char *arg1, ...);
&ffi_type_uint, types) == FFI_OK) {
ffi_call(&cif, (void (*)()) printf, &result, values);
} else {
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
free(types);
free(values);
free(args);
return NULL;
PyErr_SetString(PyExc_RuntimeError, "Whoa!!!!!");
SWIG_fail;
}
free(types);
free(values);

View file

@ -69,7 +69,7 @@ extern int gcdmain(int argc, char *argv[]);
PyObject *utf8str;
if (!PyUnicode_Check($input)) {
PyErr_SetString(PyExc_ValueError,"Expected a string");
return NULL;
SWIG_fail;
}
utf8str = PyUnicode_AsUTF8String($input);
PyBytes_AsStringAndSize(utf8str, &cstr, &len);
@ -79,7 +79,7 @@ extern int gcdmain(int argc, char *argv[]);
%#else
if (!PyString_Check($input)) {
PyErr_SetString(PyExc_ValueError,"Expected a string");
return NULL;
SWIG_fail;
}
$1 = PyString_AsString($input);
$2 = (int)PyString_Size($input);

View file

@ -50,7 +50,7 @@ namespace test {
PyComplex_ImagAsDouble($input));
} else {
PyErr_SetString(PyExc_TypeError,"Expected test_complex.\n");
return NULL;
SWIG_fail;
}
}
%typemap(freearg) test::test_complex * {
@ -242,7 +242,7 @@ namespace Split {
$1 = PyInt_AsLong($input);
if ($1 < 0) {
PyErr_SetString(PyExc_ValueError,"domain error\n");
return NULL;
SWIG_fail;
}
}
#endif

View file

@ -11,7 +11,7 @@
argc = PyTuple_Size(varargs);
if (argc > 10) {
PyErr_SetString(PyExc_ValueError, "Too many arguments");
return NULL;
SWIG_fail;
}
for (i = 0; i < argc; i++) {
PyObject *pyobj = PyTuple_GetItem(varargs, i);
@ -20,7 +20,7 @@
PyObject *pystr;
if (!PyUnicode_Check(pyobj)) {
PyErr_SetString(PyExc_ValueError, "Expected a string");
return NULL;
SWIG_fail;
}
pystr = PyUnicode_AsUTF8String(pyobj);
str = strdup(PyBytes_AsString(pystr));
@ -28,7 +28,7 @@
%#else
if (!PyString_Check(pyobj)) {
PyErr_SetString(PyExc_ValueError, "Expected a string");
return NULL;
SWIG_fail;
}
str = PyString_AsString(pyobj);
%#endif