Error handling when embedding python...

Dave Cole djc at object-craft.com.au
Fri Jan 24 14:51:23 CET 2003


>>>>> "Martin" == Martin v Löwis <martin at v.loewis.de> writes:

Martin> Axel Schlueter wrote:
>> while trying to embed python as a scripting possibility into my
>> application, I stumbled across error handling. If python finds a
>> syntax error, the interpreter prints its error messages to stderr,
>> but I would like to open my own error dialog box containing the
>> message. Is there anything like an error callback hook or something
>> ?

Martin> How do you invoke the Python code? Python will not, normally,
Martin> print an error on stderr, but will return a NULL value from
Martin> the API, with a SyntaxError set.

This is a test program I wrote when I embedded Python (on Windows).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <stdlib.h>
#include <stdarg.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

#include <Python.h>

static PyObject *traceback_module;
static PyObject *string_module;

static PyObject *winmain_func;

static PyObject *import_module(char *name)
{
	PyObject *str, *module;
	char msg[128];

	str = PyString_FromString(name);
	if (str == NULL)
		return NULL;
	module = PyImport_Import(str);
	Py_DECREF(str);
	if (module == NULL) {
		sprintf(msg, "Could not import %s module", name);
		MessageBox(NULL, msg, "Python Error", MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
		return NULL;
	}

	return module;
}

static void python_error()
{
	PyObject *exc = NULL, *value = NULL, *trace = NULL,
		*func = NULL,
		*lines = NULL,
		*str = NULL,
		*obj = NULL;

	// exc, value, trace = sys.exc_info()
	PyErr_Fetch(&exc, &value, &trace);

	// import traceback
	if (traceback_module == NULL)
		traceback_module = import_module("traceback");
	if (traceback_module == NULL)
		goto error;

	// lines = traceback.format_exception(exc, value, trace, 20)
	obj = PyModule_GetDict(traceback_module);
	func = PyDict_GetItemString(obj, "format_exception");
	Py_DECREF(obj); obj = NULL;
	if (func == NULL)
		goto error;
	lines = PyObject_CallFunction(func, "OOOi", exc, value, trace, 20);
	if (lines == NULL)
		goto error;
	Py_DECREF(func); func = NULL;

	// import string
	if (string_module == NULL)
		string_module = import_module("string");
	if (string_module == NULL)
		goto error;

	// str = string.join(lines)
	obj = PyModule_GetDict(string_module);
	func = PyDict_GetItemString(obj, "join");
	Py_DECREF(obj); obj = NULL;
	if (func == NULL)
		goto error;
	str = PyObject_CallFunction(func, "O", lines);
	if (str == NULL)
		goto error;
	Py_DECREF(func); func = NULL;

	MessageBox(NULL, PyString_AsString(str), "Python Error", MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);

error:
	Py_XDECREF(exc); Py_XDECREF(value); Py_XDECREF(trace);
	Py_XDECREF(func);
	Py_XDECREF(lines);
	Py_XDECREF(str);
	Py_XDECREF(obj);

	PyErr_Clear();
}

static void python_init_module(char *name)
{
	PyObject *obj = NULL, *mod = NULL, *dict = NULL;

	Py_Initialize();

	obj = PyString_FromString(name);
	if (obj != NULL) {
		mod = PyImport_Import(obj);
		if (PyErr_Occurred())
			mod = NULL;
	}
	if (mod != NULL)
		dict = PyModule_GetDict(mod);
	if (dict != NULL)
		winmain_func = PyDict_GetItemString(dict, "winmain");

	Py_XDECREF(obj);
	Py_XDECREF(mod);
	Py_XDECREF(dict);
}

int APIENTRY WinMain(HINSTANCE inst, HINSTANCE prev_inst, LPSTR cmd_line, int cmd_show)
{
	PyObject *obj;
	int ret;

	python_init_module(cmd_line);
	if (winmain_func == NULL) {
		python_error();
		return 0;
	}

	ret = 0;
	obj = PyObject_CallFunction(winmain_func, "iisi", inst, prev_inst, cmd_line, cmd_show);
	if (obj != NULL)
		ret = PyInt_AsLong(obj);
	Py_XDECREF(obj);
	if (PyErr_Occurred())
		python_error();

	return ret;
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Because I am also an idiot I fiddled around with making a swig-free
thin wrapper around some of the Platform SDK (don't ask).

Here is the Hello Windows program...

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
from sdk32 import *

ps = PAINTSTRUCT()
rect = RECT()
def wnd_proc(wnd, msg, wparam, lparam):
    global ps, rect
    if msg == WM_PAINT:
        dc = BeginPaint(wnd, ps)
        GetClientRect(wnd, rect)

        DrawText(dc, 'Hello Windows!', -1, rect,
                 DT_SINGLELINE | DT_CENTER | DT_VCENTER)

        EndPaint(wnd, ps)
        return 0

    elif msg == WM_DESTROY:
        PostQuitMessage(0)
        return 0

    return DefWindowProc(wnd, msg, wparam, lparam)

def winmain(inst, prev_inst, cmd_line, cmd_show):
    app_name = 'HelloWin'

    wc = WNDCLASSEX()
    wc.style = CS_HREDRAW | CS_VREDRAW
    wc.wnd_proc = wnd_proc
    wc.inst = inst
    wc.cursor = LoadCursor(0, IDC_ARROW)
    wc.background = GetStockObject(WHITE_BRUSH)
    wc.name = app_name
    RegisterClassEx(wc)

    wnd = CreateWindow(app_name, 'The Hello Program', WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT, CW_USEDEFAULT,
                       CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, inst, 0)

    ShowWindow(wnd, cmd_show)
    UpdateWindow(wnd)

    msg = MSG()
    while 1:
        if not GetMessage(msg, 0, 0, 0):
            break
        TranslateMessage(msg)
        DispatchMessage(msg)
    return msg.wparam

if __name__ == '__main__':
    winmain(GetModuleHandle(None), 0, '', SW_SHOWNORMAL)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

-- 
http://www.object-craft.com.au




More information about the Python-list mailing list