[C++-sig] Have error_already_set - now what?

Achim H. achim-bpl at mol-net.com
Fri Jan 12 10:50:32 CET 2007


Am Donnerstag, 11. Januar 2007 18:50 schrieb Johan Johansson:
> It's probably just me missing something obvious, but I'm having a very hard
> time to get a useful error message when I catch an error_already_set in
> code calling a python function/method. 
[..]

> What's a good way to find out what error occurred (exhaustively matching
> doesn't strike me as good).

I had the same problem and additionally, I did not want to pollute stderr as 
my project has its own logging system. This hacked beast is what I came up 
with. AFAIK, it works for Python 2.3 - 2.5 but as it's using python 
internals, that's not something to be relied on for the future.

Achim.

typedef struct _traceback { 
	PyObject_HEAD
	struct _traceback *tb_next;
	struct _frame *tb_frame;
	int tb_lasti;
	int tb_lineno;
} PyTracebackObject; // stolen from python source, not in normal headers

std::string printTB(PyObject *f)
{
	PyTracebackObject *tb = (PyTracebackObject *)f;
	int err = 0;
	std::ostringstream os;
	while (tb != NULL && err == 0)
	{
		os << "  File \x22"<<PyString_AsString(tb->tb_frame->f_code->co_filename)
		   << "\x22, line "<<tb->tb_lineno<<", in "
		   << PyString_AsString(tb->tb_frame->f_code->co_name)
		   << "\n";
		tb = tb->tb_next;
		if (err == 0)
			err = PyErr_CheckSignals();
	}
	os.flush();
	return os.str();
}

std::string getPythonException()
{
	PyObject* type = 0;
	PyObject* value = 0;
	PyObject* tb = 0;
	PyErr_Fetch(&type,&value,&tb);

	try {
		handle<> type_o( allow_null(type) );
		handle<> value_o(value);
		handle<> tb_o( allow_null(tb) );

		handle<> type_str(PyObject_Str(type_o.get()));
		handle<> value_str(PyObject_Str(value_o.get()));
		handle<> tb_str(PyObject_Str(tb_o.get()));

		std::string ret = "Error in python execution:\n";
		if (tb_str.get()!=0)
			ret += "Traceback (most recent call last):\n" + printTB(tb_o.get());

		std::string type_string = PyString_AsString(type_str.get());
		if (type_string.find("exceptions.")==0)
			type_string=type_string.substr(11);
		ret += type_string + ": ";
		ret += PyString_AsString(value_str.get());
		ret += "\n";
		return ret;
	}
	catch (error_already_set&)
	{
		return "Error during python exception elucidation.";
	}
}



More information about the Cplusplus-sig mailing list