Making Python Scripts Show Windows-friendly Errors/Stacktrace

Most of us love to distribute our python programs to others once you have finished coding a neat little script. For Windows users we package it using Py2exe or cx_freeze. However, many of the end-users will not be happy with a black command window popping up, say, when an error is thrown.

Of course the alternative is to write a full blown GUI application using WXPython or PyFLTK. Even the latter, though quite lightweight, adds several megabytes to the distribution, when all you need is a simple message-box indicating an error or showing some informational text. Clearly, its an overkill for your throwaway python scripts.

This is the kind of problem I typically face and I have found a good solution. The answer is ctypes library which comes as a part of the standard distribution from Python 2.5 onwards. It simply calls the messagebox function from user32.dll (which is always present in a windows installation). With the main problem solved, what remained was to obtain the error text and stack trace.

Let’s see how the code looks like:

# Importing all the works for a native Win32 Message Box
from ctypes import c_int, WINFUNCTYPE, windll
from ctypes.wintypes import HWND, LPCSTR, UINT
prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)
 # For printing the stack
import sys
import traceback
from time import sleep

def show_popup(text):
    print text
    MessageBox(text=text, caption="Sample App Says...")

def mainloop():
    raise "Uff!"

if __name__ == '__main__':
    try:
        mainloop()
    except:
        type, value, sys.last_traceback = sys.exc_info()
        lines = traceback.format_exception(type, value,sys.last_traceback)
        show_popup("Aiyooooo..... there has been an error!\n" +
            "Exception in user code:\n" +
            "".join(lines) +
            "===== Please mail a screenshot to arunvr@gmail.com ===="
            )
    finally:
        sleep(1) # show the console output for a second so that users can read it

EDIT: This is how it looks like in PyMail, one of my scripts-that-grew-into-an-app ;)

Screenshot of a Python Stacktrace in a Messagebox

Hi! Welcome to ArunRocks, an odd collection of writeups on programming, travel, gadgets and practically anything under the sun. This state of affairs could be blamed on the ecelectic interests of your host, Arun Ravindran. He loves programming in several languages especially Python. He is currently a developer member of the Django Software Foundation. Read more...

Comments