wxPython - Can you explain why I crash

Miki Tebeka tebeka at cs.bgu.ac.il
Wed Apr 9 10:52:45 EDT 2003


Hello All,

I've written this little client. It used to work fine but now no
matter which button I press the application crash.
I'm running Python2.2 and wxPython 2.4.0.7
Any ideas?

10x.
Miki

--- ui.py ---
#!/usr/bin/env python
'''Compas client emulator UI'''

__author__ = 'Miki Tebeka <miki_tebeka at amat.com>'
__id__ = '$Id: ui.py,v 1.3 2003/03/06 14:20:15 MTebeka90603 Exp $'

# $Source: /u/CVSROOT/compass_client/ui.py,v $

from wxPython.wx import *
from os.path import isfile
from ConfigParser import ConfigParser
import client

# Ids
ID_GET_RECIPES = wxNewId()
ID_SELECT_RECIPE = wxNewId()
ID_GET_WAFERS = wxNewId()
ID_LOAD = wxNewId()
ID_UNLOAD = wxNewId()
ID_RUN = wxNewId()
ID_STOP = wxNewId()
ID_DISCONNECT = wxNewId()
ID_CONNECT = wxNewId()
ID_LAST_ERROR = wxNewId()
ID_STATUSBAR = wxNewId()
ID_SELECT_ALIGN = wxNewId()

# Connection messages
CONNECTED = 'Connected'
DISONNECTED = 'Disconnected'

class CompassClient(wxFrame):
    '''Client frame'''
    def __init__(self):
        # No resizable border
        wxFrame.__init__(self, None, -1, 'CompassSim',
                         style=wxDEFAULT_FRAME_STYLE &
(~wxRESIZE_BORDER))
        self.CreateStatusBar(1, 0, ID_STATUSBAR)
        self.GetStatusBar().SetFieldsCount(2)
        # Get mouse click on task bar
        EVT_LEFT_DOWN(self.GetStatusBar(), self.last_error)

        sizer = wxBoxSizer(wxVERTICAL)
        # Recipe list
        t = wxStaticText(self, -1, 'Recipes:')
        sizer.Add(t)
        self.recipes = wxListBox(self, -1)
        sizer.Add(self.recipes, 0, wxEXPAND)
        hsizer = wxBoxSizer(wxHORIZONTAL)
        self.add_button(ID_GET_RECIPES, 'Read Data', self.get_recipes,
hsizer)
        self.add_button(ID_SELECT_RECIPE, 'Select',
self.select_recipe, \
                        hsizer)
        sizer.Add(hsizer)
        self.add_sep(sizer)
        # Wafer List
        t = wxStaticText(self, -1, 'Wafers:')
        sizer.Add(t)
        self.wafers = wxListBox(self, -1, style=wxLB_EXTENDED)
        sizer.Add(self.wafers, 0, wxEXPAND)

        # Load / Unload
        hsizer = wxBoxSizer(wxHORIZONTAL)
        self.add_button(ID_LOAD, 'Load', self.load, hsizer)
        self.add_button(ID_UNLOAD, 'Unload', self.unload, hsizer)
        sizer.Add(hsizer)
        
        # Run / Stop
        self.add_sep(sizer)
        hsizer = wxBoxSizer(wxHORIZONTAL)
        self.add_button(ID_RUN, 'Run', self.run, hsizer)
        self.add_button(ID_STOP, 'Stop', self.stop, hsizer)
        sizer.Add(hsizer)
        self.times = wxSpinCtrl(self, -1, size=(75,-1))
        self.times.SetRange(1, 999999)
        self.times.SetValue(1)
        sizer.Add(self.times)
        self.add_sep(sizer)

        # Connect / Quit
        hsizer = wxBoxSizer(wxHORIZONTAL)
        self.add_button(ID_CONNECT, 'Connect', self.connect, hsizer)
        self.add_button(-1, 'Quit', lambda e: self.Close(1), hsizer)
        sizer.Add(hsizer)
        
        # Auto resize      
        self.SetSizer(sizer)
        self.SetAutoLayout(1)
        sizer.Fit(self)
        self.connect(None)


    def status(self, success):
        '''Status of last commands'''
        if success:
            self.SetStatusText('OK', 1)
        else:
            self.SetStatusText('Error', 1)

    def busy(self):
        '''Busy state'''
        self.SetCursor(wxHOURGLASS_CURSOR)

    def idle(self):
        '''Idle state'''
        self.SetCursor(wxSTANDARD_CURSOR)

    def add_button(self, id, title, func, sizer, center = 0):
        '''Add a button to sizer'''
        b = wxButton(self, id, title)
        EVT_BUTTON(self, id, func)
        if center:
            sizer.Add(b, 0, wxALIGN_CENTER)
        else:
            sizer.Add(b)
    
    def add_sep(self, sizer):
        '''Add a seperator to sizer'''
        sizer.Add(0, 5, 0, wxEXPAND)

    def error(self, msg):
        '''Show error message'''
        dlg = wxMessageDialog(self, msg, 'Error', \
                              wxOK | wxICON_EXCLAMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def last_error(self, e):
        '''Show last error'''
        err = client.LAST_ERROR
        if not err:
            err = 'Unknown Error'
        dlg = wxMessageDialog(self, err, 'Last Error', \
                              wxOK | wxICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()
    
    def get_recipes(self, e):
        '''Get recipe list'''
        print 'get_recipes'
        try:
            self.busy()
            if not client.get_lot_data():
                self.status(0)
                return
            recipes = client.get_recipe_list()
            if not recipes:
                self.status(0)
                return
            # Update listbox
            self.recipes.Clear()
            for recipe in recipes:
                self.recipes.Append(recipe)
            self.status(1)
        finally:
            self.idle()
        
    def select_recipe(self, e):
        '''Select a recipe'''
        try:
            self.busy()
            if self.recipes.GetCount() == 0:
                self.error('No Recipes')
                return
            if not client.select_recipe(self.recipes.GetStringSelection()):
                self.status(0)
                return
            wafers = client.get_wafer_list()
            if not wafers:
                self.status(0)
                return
            # Update listbox
            self.wafers.Clear()
            for wafer in wafers:
                self.wafers.Append(wafer)
            self.status(1)
        finally:
            self.idle()
    
    def _load(self, wafer):
        # set_alignment_parameters must bee called before load
        # Image must have /work/wf prefix (see stub_functions.cpp
AlignData)
        params = ['/work/wf/coarse.img', 'TIFF', # Name and format
                  '1.634888', '1.660389', # Pixel size
                  '-264.066777', '-9704.485647', # Center to Coarse
                  '-24.486192', '-21.873070', # Coarse to fine
                  '-21.873070', '5.359366', # Corner to Fine
                  '1'] # Unpatterned
        if not client.set_alignment_parameters(*params):
            client.LAST_ERROR = "Can't set alignment data"
            return 0
        return client.load(wafer)

    def load(self, e):
        '''Load wafer'''
        try:
            self.busy()
            if self.wafers.GetCount() == 0:
                self.error('No Wafers')
                return
            if len(self.wafers.GetSelections()) != 1:
                self.error('Please select only one wafer')
                return
            wafer = self.wafers.GetString(self.wafers.GetSelections()[0])
            self.status(self._load(wafer))
        finally:
            self.idle()
        
    def unload(self, e):
        '''Unload wafer'''
        try:
            self.busy()
            self.status(client.unload())
        finally:
            self.idle()

    def run(self, e):
        '''Run process for given number of iterations'''
        try:
            self.busy()
            wafers = map(lambda i: self.wafers.GetString(i), \
                                   self.wafers.GetSelections())
            for t in range(self.times.GetValue()):
                for wafer in wafers:
                    if not self._load(wafer):
                        self.status(0)
                        return
                    if not client.start_process():
                        self.status(0)
                        return
                    if not client.unload():
                        self.status(0)
                        return
            self.status(1)
        finally:
            self.idle()

    def stop(self, e):
        '''Stop process'''
        try:
            self.busy()
            self.status(client.stop())
        finally:
            self.idle()

    def connect(self, e):
        '''Connect to tcp server'''
        try:
            self.busy()
            if not client.connect():
                self.connected = 0
                self.SetStatusText(DISONNECTED)
                return
            self.SetStatusText(CONNECTED)
        finally:
            self.idle()


def main():
    app = wxPySimpleApp()
    frame = CompassClient()
    frame.Show(1)
    app.MainLoop()

# Main
if __name__ == '__main__':
    main()

--- ui.py ---

--- client.py ---

'''Compas client emulator'''

__author__ = 'Miki Tebeka <miki_tebeka at amat.com>'
__id__ = '$Id: client.py,v 1.5 2003/03/06 14:20:15 MTebeka90603 Exp $'

# $Source: /u/CVSROOT/compass_client/client.py,v $

from socket import error as SocketError, socket, AF_INET, SOCK_STREAM
import re
from xml.dom.minidom import parseString
from sys import exit

SOCKET = None # Global socket
HOST = 'localhost' # Host name
PORT = 3333 # Port
LAST_ERROR = '' # Last error

def header(name):
    '''Create header xml'''
    return '<Header To="BEE" From="WF" Type="Request" Name="%s"/>' %
name

def connect():
    '''Connect to tcp server'''
    global SOCKET, LAST_ERROR
    SOCKET = socket(AF_INET, SOCK_STREAM)
    try:
        SOCKET.connect((HOST, PORT))
        return 1
    except SocketError, e:
        LAST_ERROR = str(e)
        SOCKET = None
        return 0

def disconnect():
    global SOCKET
    SOCKET = None

def is_connected():
    global SOCKET
    return SOCKET != None

def _send(msg):
    '''send "len msg"'''
    SOCKET.sendall('%d %s' % (len(msg), msg))

# Regular expressions
NUM_RE = re.compile('\d')
WS_RE = re.compile('\s')

def _read():
    '''Read message. Return error + extra'''
    size = ''
    while 1:
        d = SOCKET.recv(1)
        if not NUM_RE.match(d):
            break
        size += d
    return _parse_respone(SOCKET.recv(int(size)))

class Error:
    '''Error class'''
    def __init__(self, value = 0, message = ''):
        self.value = value # Error value
        self.message = message # Error message

    def __repr__(self):
        return 'Error (%d): %s' % (self.value, self.message)

    def ok(self):
        '''True not error occured'''
        return self.value == 0

def _parse_respone(msg):
    '''Parse a respone. Return error + extra'''
    global LAST_ERROR
    doc = parseString(msg)
    datanode = doc.getElementsByTagName('Data')[0]
    assert(len(datanode.childNodes) in [1,2])
    errnode = None
    for node in datanode.childNodes:
        if node.nodeName == 'Error':
            errnode = node
            datanode.removeChild(node)
            break
    assert(errnode)
    attrs = errnode.attributes
    err = Error(int(attrs['ErrNum'].value), attrs['ErrText'].value)
    LAST_ERROR = err.message
    if len(datanode.childNodes):
        extra = datanode.childNodes[0]
    else:
        extra = None
    return err, extra

def _simple_cmd(msg):
    '''Simple command'''
    if not SOCKET:
        return 0
    _send(msg)
    err, extra = _read()
    return err.ok()

def _list_cmd(msg):
    '''Command that returns a list'''
    if not SOCKET:
        return 0
    _send(msg)
    err, extra = _read()
    if not err.ok():
        return []
    else:
        return map(lambda n: n.nodeValue, extra.attributes.values())

def _state_cmd(msg):
    '''Command that returns a state'''
    if not SOCKET:
        return 0
    _send(msg)
    err, extra = _read()
    if not err.ok():
        return -1
    return int(extra.attributes['Value'].nodeValue)
    
# Interface functions    
def get_lot_data():
    '''Get lot data'''
    return _simple_cmd(header('GetLotData'))

def get_recipe_list():
    '''Get recipe list'''
    print 'get_recipe_list'
    return _list_cmd(header('GetRecipeList'))

def select_recipe(recipe):
    '''Select a recipe'''
    msg = header('SelectRecipe')
    msg += '<Data><Recipe Name="%s"/></Data>' % recipe
    return _simple_cmd(msg)

def get_wafer_list():
    '''Get wafer list'''
    return _list_cmd(header('GetWafersList'))

def set_alignment_parameters(*params):
    '''Set alignment parameters'''
    assert(len(params) == 11)
    msg = header('AlignData') + '''
<Data>
    <CoarseImage Name="%s" Format="%s"/>
    <CoarsePixelSize psX="%s" psY="%s"/>
    <CenterToCoarse CntrToCrsX="%s" CntrToCrsY="%s"/>
    <CoarseToFine CrsToFineX="%s" CrsToFineY="%s"/>
    <CornerToFine CrnToFineX="%s" CrnToFineY="%s"/>
    <WaferType UnPatternedWafer="%s"/>
</Data>''' % params
    return _simple_cmd(msg)

def prepare_to_load(slot):
    '''Prepare to load'''
    msg = header('PrepareToLoad')
    msg += '<Data><Slot SlotID="%s"/></Data>' % slot
    return _simple_cmd(msg)

def load_ended():
    '''Load ended'''
    return _simple_cmd(header('LoadEnded'))

def load(slot):
    '''Load sequence'''
    if not prepare_to_load(slot):
        return 0
    return load_ended()

def start_process():
    '''Start process'''
    return _simple_cmd(header('StartProcess'))

def prepare_to_unload():
    '''Prepare to unload'''
    return _simple_cmd(header('PrepareToUnload'))

def unload_ended():
    '''Unload ended'''
    return _simple_cmd(header('UnloadEnded'))
    
def unload():
    '''Unload sequence'''
    if not prepare_to_unload():
        return 0
    return unload_ended()

def get_state():
    '''Get state'''
    return _state_cmd(header('GetState'))

def get_vacuum_state():
    '''Get vacuum state'''
    return _state_cmd(header('GetVacuumState'))

def stop():
    '''Stop'''
    return _simple_cmd(header('bee_stop_process'))

--- client.py ---




More information about the Python-list mailing list