I am trying to make a Python iterator in boost::python. So I have a function
PyObject *my_iterator_next(MyIterator *iter) {
if (!iter->is_end()) {
return *(*iter)++;
}
else {
PyErr_SetNone(PyExc_StopIteration);
// this doesn't work either
// PyErr_SetString(PyExc_StopIteration, "end of collection");
return NULL;
}
}
In Python:
// x is MyContainer([1, 2, 3])
for x in my_container:
print(x)
And I get:
1
2
3
NoneTraceback (most recent call last):
File "main.py", line 6, in <module>
print(x)
StopIteration: end of collection
Also
it = my_collection.__iter__()
try:
it.__next__();
it.__next__();
it.__next__();
it.__next__();
except:
print("caught exception")
This code doesn't print anything, so no type of exception is caught.
Why?
After setting the Python exception, you must notify Boost.Python like this:
throw_error_already_set();
See http://www.boost.org/doc/libs/1_35_0/libs/python/doc/v2/errors.html
Related
I use llvmlite to translate try ... except ..., when I use function landingpad, it can generate IR, but throw an error when verifying it, I already search docs about this, I find it was moved(https://github.com/numba/llvmlite/pull/156), I can't solve it, help...
demo code:
try:
e = a * b
f = 2 / 3
print(e)
except Exception as e:
# pass
print(e)
source code:
def translate_except(self, builder_except):
tp_pers = ir.FunctionType(ir.IntType(8), (), var_arg=True)
pers = ir.Function(self.module, tp_pers, '__gxx_personality_v0')
landingpad = builder_except.landingpad(ir.LiteralStructType([ir.IntType(32), ir.IntType(8).as_pointer()]),
'lp')
int_typeinfo = ir.GlobalVariable(builder_except.function.module, ir.IntType(8).as_pointer(),
"_ZTIi")
int_typeinfo.global_constant = True
int_typeinfo.linkage = 'internal'
int_typeinfo.unnamed_addr = True
landingpad.add_clause(ir.CatchClause(int_typeinfo))
landingpad.add_clause(ir.FilterClause(ir.Constant(ir.ArrayType(int_typeinfo.type, 1),
[int_typeinfo])))
return landingpad
...
...
...
# vevify
mod = llvm.parse_assembly(str(handle_bc.module))
mod.verify()
print('verify Done.')
gen IR:
...
...
except.11233:
%"lp" = landingpad {i32, i8*}
catch i8** #"_ZTIi"
filter [1 x i8**] [i8** #"_ZTIi"]
%"11244" = load i32, i32* %"e.4", align 8
call void (...) #"print"(i32 %"11244")
resume {i32, i8*} %"lp"
...
...
verify it still throw this, :
Traceback (most recent call last):
File "D:/python/bc2ir/BC_TO_IR.py", line 317, in main
mod.verify()
File "C:\Python\lib\site-packages\llvmlite\binding\module.py", line 115, in verify
raise RuntimeError(str(outmsg))
RuntimeError: LandingPadInst needs to be in a function with a personality.
%lp = landingpad { i32, i8* }
catch i8** #_ZTIi
filter [1 x i8**] [i8** #_ZTIi]
Instruction does not dominate all uses!
%e.4 = alloca i32, i32 8
%"11244" = load i32, i32* %e.4, align 8
ResumeInst needs to be in a function with a personality.
resume { i32, i8* } %lp
I have database with a single table Person which has a name(str) and age(int) columns. So, I create simple validate function for my sqlite3.connection
def adult(age):
return age > 18
And with following code, it works fine
connection = sqlite3.connect(r'C:\Dev\Garbage\database.db')
with connection:
connection.create_function('adult', 1, adult)
cursor = connection.cursor()
persons = cursor.execute('select "p"."name", "p"."age" from "Person" "p" where adult("p"."age")').fetchall()
for person in persons:
print(person)
But if I change adult like this
def adult(age):
return 1 / 0
I will get sqlite3.OperationalError: user-defined function raised exception.
In my project, it might be a huge amount of functions and I'd like to know - is there any way to know which function raised an exception? Or get ZeroDivisionError: division by zero instead of this.
Python's sqlite3 module throws away any error information from the exception, and replaces it with the constant message you've seen:
void _pysqlite_func_callback(sqlite3_context* context, int argc, sqlite3_value** argv)
{
...
py_func = (PyObject*)sqlite3_user_data(context);
args = _pysqlite_build_py_params(context, argc, argv);
if (args) {
py_retval = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
ok = 0;
if (py_retval) {
ok = _pysqlite_set_result(context, py_retval) == 0;
Py_DECREF(py_retval);
}
if (!ok) {
if (_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
}
sqlite3_result_error(context, "user-defined function raised exception", -1);
}
...
}
I don't know what prevents it from appending the exception message to the returned error message.
Anyway, it is possible to print out the inner stack trace by calling enable_callback_tracebacks:
import sqlite3
db = sqlite3.connect(':memory:')
def error():
raise Exception('hello')
db.create_function('error', 0, error)
sqlite3.enable_callback_tracebacks(True) # <-- !
db.execute('select error()')
Traceback (most recent call last):
File "<stdin>", line 1, in error
Exception: hello
Traceback (most recent call last):
File "<stdin>", line 1, in
sqlite3.OperationalError: user-defined function raised exception
How to determine in what function exception was raised. For example exist two functions: 'foo' and 'bar'. In 'foo' exception will raised randomly.
import random
def foo():
if random.randint(1, 10) % 2:
raise Exception
bar()
def bar():
raise Exception
try:
foo()
except Exception as e:
print "Exception raised in %s" % ???
import inspect
try:
foo()
except Exception as e:
print "Exception raised in %s" % inspect.trace()[-1][3]
I use the traceback module, like so:
import traceback
try:
1 / 0
except Exception:
print traceback.format_exc()
This gives the following output:
Traceback (most recent call last):
File "<ipython-input-3-6b05b5b621cb>", line 2, in <module>
1 / 0
ZeroDivisionError: integer division or modulo by zero
If the code runs from a file, the traceback will tell the line and character number of where the error occured :)
EDIT:
To accomodate the comment from Habibutsu: Yes, it's useful for printing, but when needed to get more info (for example function name) - not suitable
The doc-pages tell you how to extract the trace programmatically: http://docs.python.org/2/library/traceback.html
From the page linked above:
>>> import traceback
>>> def another_function():
... lumberstack()
...
>>> def lumberstack():
... traceback.print_stack()
... print repr(traceback.extract_stack())
... print repr(traceback.format_stack())
...
>>> another_function()
File "<doctest>", line 10, in <module>
another_function()
File "<doctest>", line 3, in another_function
lumberstack()
File "<doctest>", line 6, in lumberstack
traceback.print_stack()
[('<doctest>', 10, '<module>', 'another_function()'),
('<doctest>', 3, 'another_function', 'lumberstack()'),
('<doctest>', 7, 'lumberstack', 'print repr(traceback.extract_stack())')]
[' File "<doctest>", line 10, in <module>\n another_function()\n',
' File "<doctest>", line 3, in another_function\n lumberstack()\n',
' File "<doctest>", line 8, in lumberstack\n print repr(traceback.format_stack())\n']
The doc-string for traceback.extract_stack is the same as for traceback.extract_tb
traceback.extract_tb(traceback[, limit])
Return a list of up to limit “pre-processed” stack trace entries
extracted from the traceback object traceback. It is useful for
alternate formatting of stack traces. If limit is omitted or None, all
entries are extracted. A “pre-processed” stack trace entry is a
quadruple (filename, line number, function name, text) representing
the information that is usually printed for a stack trace. The text is
a string with leading and trailing whitespace stripped; if the source
is not available it is None.
What is your goal? If you are worried about bar and foo throwing the same exception type and the caller not being able to differentiate between them, just derive a new exception class:
import random
class FooException(Exception):
"""An exception thrown only by foo."""
def foo():
if random.randint(1,10) % 2:
raise FooException
bar()
def bar():
raise Exception
try:
foo()
except FooException:
print "Exception raised in foo..."
except:
print "Exception raised in bar (probably)..."
I am wrapping a C lib to python module using SWIG. But exception does not seem to be raised at the right place, I have a simple demo for this,
except_test.i
%module except_test
%{
#include "except_test.h"
#include <stdio.h>
%}
%{
static int flagged_exception = 0;
void throw_except()
{
flagged_exception = 1;
printf("flag set \n");
}
%}
%exception {
$action
printf("exception block\n");
if (flagged_exception) {
printf("before setstring\n");
PyErr_SetString(PyExc_RuntimeError, "test except");
printf("after setstring\n");
flagged_exception = 0;
}
}
%include "except_test.h"
except_test.c
#include "except_test.h"
int except_test(int a) {
if (a < 0) {
throw_except();
return 0;
} else{
return -1;
}
}
run_except.py
from except_test import *
import time
def test():
b = except_test(-1)
print 'b=', b
try:
test()
except:
print "caught exception"
for i in range(10):
print i
time.sleep(1)
Now if I run run_except.py
$python run_except.py
flag set
exception block
before setstring
after setstring
b= 0
0
Traceback (most recent call last):
File "run_except.py", line 15, in <module>
time.sleep(1)
RuntimeError: test except
as the output shows, the try/catch block didn't catch the exception.
Why is this? and How to avoid this?
Thanks,
You have to return NULL from a Python extension to have it notice the error immediately:
if (flagged_exception) {
PyErr_SetString(PyExc_RuntimeError, "test except");
flagged_exception = 0;
return NULL;
}
But using the generic SWIG macros will make the SWIG interface more portable to other languages.
You need to put SWIG_fail; right after PyErr_SetString. Alternatively, there is a convenient (and what's more important language-independent) macro SWIG_exception(SWIG_RuntimeError, "error message") wrapping PyErr_SetString and SWIG_fail.
I have a C dll that exports this function:
DECLDIR int runTest (char *historyPath, unsigned int candleNumber, void (*testUpdate)(double percentageOfTestCompleted), void (*testFinished)(void), char **error);
I'm trying to use the function inside my python script this way:
historyFilePath_c = c_char_p(historyFilePath)
candleNumber_c = c_int(1000)
error_c = c_char_p(300);
TEST_UPDATE = CFUNCTYPE(c_int, POINTER(c_double))
testUpdate_c = TEST_UPDATE(testUpdate)
TEST_FINISHED = CFUNCTYPE(c_int)
testFinished_c = TEST_FINISHED(testFinished)
astdll.runTest (historyFilePath_c, candleNumber_c, testUpdate_c, testFinished_c, byref(error_c))
def testUpdate(percentageOfTestCompleted):
print 'Test running ' , percentageOfTestCompleted[0]
return True
def testFinished():
print 'Test finished!!'
return True
I'm getting this error (several times because the callback function is running many times. I'll leave just the last error. All of them are the same)
Test running
Traceback (most recent call last):
File "_ctypes/callbacks.c", line 314, in 'calling callback function'
File "ast.py", line 67, in testUpdate
print 'Test running ' , percentageOfTestCompleted[0]
ValueError: NULL pointer access
Test finished!!
The testUpdate callback takes a double by value, not a pointer, and both callbacks return void, i.e. None.
candleNumber_c is unnecessary, especially if you declare argtypes. The same applies to historyFilePath_c. A Python string already contains a pointer to a null-terminated string, which is what the c_char_p constructor uses.
Why do you initialize error_c to the address 300?
Here's an example that should help:
tmp.py:
from ctypes import *
lib = CDLL('./tmp.so')
c_test_update_t = CFUNCTYPE(None, c_double)
c_test_finished_t = CFUNCTYPE(None)
run_test = lib.runTest
run_test.argtypes = [
c_char_p, c_uint, c_test_update_t, c_test_finished_t,
POINTER(c_char_p)]
def test_update(percent_completed):
print 'percent completed:', percent_completed
test_update_c = c_test_update_t(test_update)
def test_finished():
print 'test finished'
test_finished_c = c_test_finished_t(test_finished)
error = c_char_p()
result = run_test(
'path/to/history', 1000, test_update_c, test_finished_c,
byref(error))
print result
print error.value
tmp.c:
#include <stdio.h>
char error_string[] = "error string";
int runTest(
char *historyPath,
unsigned int candleNumber,
void (*testUpdate)(double percentageOfTestCompleted),
void (*testFinished)(void),
char **error)
{
printf("historyPath: %s\n", historyPath);
printf("candleNumber: %d\n", candleNumber);
testUpdate(0.0);
testFinished();
*error = error_string;
return 0;
}
(Just a simple test lib, compiled with gcc on Linux)
Output:
historyPath: path/to/history
candleNumber: 1000
percent completed: 0.0
test finished
0
error string