import time from MeteorClient import MeteorClient client = MeteorClient('ws://127.0.0.1:3000/websocket', debug=True) client.connect() client.subscribe('SessionsList') time.sleep(1) sessions = client.find('sessions') print(sessions) time.sleep(1)
class MWorker: multiprocessPluginManager = "" # yapsy manager meteorClient = "" # python-meteor client # session=requests.Session() #http client meteorUrl = "ws://127.0.0.1:3000/websocket" CYCLE_DEFAULT_DELAY = 20 # 10 seconds SYNCHRO_TIMEOUT = 10 # meteor functions are asynchron. this is delay for how long i should wait till # it is considered as fail... 2 sec are default subscription_status = {} # this will assure, subscription is ready... "subscription_name":true/false workername = "localhostworker" # this is worker name - this must be initialised at moment of start, and # must by uniqued... data = "" error = "" syncwaitdone = False def __init__(self, meteorUrl): """ constructor :return: """ self.meteorUrl = meteorUrl self.logm("MWorker:constructor", "python meteor client initialisation:") self.initMeteorConnect() self.logm("MWorker:constructor", "getting unassigned") # self.infiniteCycle() self.getUnassigned() def infiniteCycle(self): """ this is to keep thread running - it can be interupted by ctrl+c :return: """ while True: try: time.sleep(1) except KeyboardInterrupt: break def initMeteorConnect(self): """ this will use library python-meteor in order to escablish session to selected meteor :return: """ self.logm("MWorkerLib:initMeteorConnect:", "meteor python lib client iniciaisation...") self.meteorClient = MeteorClient('ws://127.0.0.1:3000/websocket', auto_reconnect=True) self.meteorClient.connect() self.subscribeCollectionSynchron(['unassigned', 'active', 'trash'], self.SYNCHRO_TIMEOUT) self.logm("MWorkerLib:initMeteorConnect:", "meteor python lib client iniciaisation done...") def meteorCollectionSubscribed(self, subscription): self.subscription_status[subscription] = True; self.logm("MWorkerLib:subscribed:", 'SUBSCRIBED {}'.format(subscription)) def meteorConnected(self): self.logm("MWorkerLib:connected:", ' CONNECTED') def initYapsy(self): """ inicialisation of yapsi subsystems... :return: """ self.multiprocessPluginManager = MultiprocessPluginManager() self.multiprocessPluginManager.setPluginPlaces(["plugins"]) self.multiprocessPluginManager.collectPlugins() self.logm("MWorkerLib:initYapsy:", "following pluggins ready") for pluginInfo in self.multiprocessPluginManager.getAllPlugins(): self.logm("MWorkerLib:initYapsy:", ">" + pluginInfo.name) def isSubscriptionProcessDone(self): """ this will check, if in self.subscription_status all collections are set to true :return: true if all requested collections are subscribed, orthervice false.. """ kk = self.subscription_status.keys() for col in kk: if self.subscription_status[col] == False: self.logm("MWorkerLib:isSubscriptionProcessDone:", self.subscription_status) return False return True def subscribeCollectionSynchron(self, collections, timeout): """ this is synchron method. this means, there is loop for "timeout" seconds, so subscription can be estalished... :param: timeout - number of seconds for cycle this function will have :param: collections - array of collections to be subscribed with self.meteorClient... ['unassigned', 'active', 'trash'] :return: will return true, or collection if some is false """ self.logm("MWorkerLib:subscribeCollectionsynchron:", "begining with subscription") self.meteorClient.on('subscribed', self.meteorCollectionSubscribed) self.meteorClient.on('connected', self.meteorConnected) for col in collections: self.subscription_status[col] = False self.meteorClient.subscribe(col) self.logm("MWorkerLib:subscribeCollectionSynchron", "subscription init done, now waiting...:" + str(self.meteorClient.subscriptions.keys())) epoch = int(time.time()) while (((int(time.time()) - epoch) < timeout) and ( (self.isSubscriptionProcessDone() == False))): try: time.sleep(1) self.logm("MWorkerLib:subscribeCollectionSynchron", "inside waiting cycle :" + str(self.meteorClient.subscriptions.keys())) except KeyboardInterrupt: break if (self.isSubscriptionProcessDone() == False): self.logm("MWorkerLib:subscribeCollectionSynchron", "some requested subscription failed...:" + str(self.subscription_status)) return False else: self.logm("MWorkerLib:subscribeCollectionSynchron", "requested subscription successfuly subscribed...") return True def getUnassigned(self): """ get list of unassigned tasks :return: list of unassigned tasks """ self.logm("MWorkerLib:getUnassigned", "geting all unassigned") all_posts = self.meteorClient.find('unassigned') self.logm("MWorkerLib:getUnassigned", "found following unassigned:" + str(all_posts)) def subscription_callback(self, error): if error: self.logm("MWorkerLib:subscription_callback", "subsribing to unassigned failed") return self.logm("MWorkerLib:subscription_callback", "subsribing to unassigned succeed") def logm(self, tag="undefined tag", text="undefined text"): """ logger wrapper .... :param tag: tag :param level: level ( 1..10 ) :param text: dscription of logging :return: """ timestamp = self.getTimestamp() print("{d} t:{a} t:{c} ".format(a=tag, c=text, d=timestamp)) ####################################### support methods def getTimestamp(self): ts = time.time() return datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') def callViewToolkit(self, method, parameters, callback): """ this will execute call... please note, for simple geting collection data, no need to create method... :param method: name of function :param parameters: what to give to viewtoolkit :callback - as all meteor calls are async, callback is required def callback_function(error, result): if error: print(error) return print(result) :return: """ self.logm("MWorkerLib:callViewToolkit", "method:" + method + " with parameters:" + parameters + " called") self.meteorClient.call(method, parameters, callback) def isPluginActiveInPluginManager(self, pluginname): """ this is to check if plugin which is parameter exist in worker, and if yes, if it is activated... :param pluginname: :return: true in case plugin is activated """ for pluginInfo in self.multiprocessPluginManager.getAllPlugins(): self.logm("MWorkerLib:isPlugginActiveInPluginManager:", "checking plugin " + pluginInfo.name + "against " + pluginname) if (pluginname == pluginInfo.name): self.logm("MWorkerLib:isPlugginActiveInPluginManager:", "plugin was found, let see if it is activated " + str(pluginInfo.is_activated)) if pluginInfo.is_activated: self.logm("MWorkerLib:isPlugginActiveInPluginManager:", "yes, plugin exist and was activated. returning true") return True self.logm("MWorkerLib:isPlugginActiveInPluginManager:", "could not found plugin you uare asking for, or it is not activated, returning False") return False def activatePlugin(self, pluginname): """ plugin activation itself :param pluginname: :return: """ self.logm("MWorkerLib:isPlugginActiveInPluginManager:activatePlugin", "plugin {a} will be activated now...".format(a=pluginname)) self.multiprocessPluginManager.activatePluginByName(pluginname) self.logm("MWorkerLib:isPlugginActiveInPluginManager:activatePlugin", "plugin {a} was activated...".format(a=pluginname)) def moveJobFromActiveToTrash(self,jobname): """ will move job by its name from active to trash :param jobname: :return: """ #kontrola, zda trash ma v sobe vytvoreneho workera: if(self.isWorkerInTrash()==False): self.createWorkerRecordInTrash() job=self.getJobInActiveByName(jobname) if (job==None): return False if self.createJobInTrashSynchronised(job): self.deleteJobFromActiveSynchronised(jobname) def deleteJobFromActiveSynchronised(self,jobname): """ delete job from active :param jobname: :return: """ result = False self.syncwaitdone = False # zacatek locku self.logm("MWorkerLib:deleteJobFromActiveSynchronised", "worker:" + self.workername + " is going to remove job from active " + str(jobname)) self.meteorClient.remove( 'active',{'_id':self.workername,'jobs._id':jobname}, callback=self.callback_synchro) res = self.syncWait() # konec locku self.logm("MWorkerLib:deleteJobFromActiveSynchronised", "worker:" + self.workername + " removed " + str(jobname)+ "result is "+str(res)) return res def createJobInTrashSynchronised(self,job): """ this will create job in trash collection under worker name... :param job: :return: """ #inseritng job self.logm("MWorkerLib:createJobInTrash", "worker:" + self.workername + " is going to insert to trash following: " + str(job)) self.syncwaitdone = False # zacatek locku self.meteorClient.update('trash', {'_id': self.workername}, {'$push': {"jobs":job}}, callback=self.callback_synchro) res = self.syncWait() # konec locku return res def getJobInActiveByName(self,jobname): """ this will get job back :param jobname: name of job in active ... :return: return job, or None """ res = self.meteorClient.find_one('active',{'_id':self.workername,'jobs.jobname':jobname}) if res==[]: return None return res def moveJobFromUnassignedToActiveSynchronised(self, jobname): """ this will shift job from unassigned to active... based on job name, which must be unique in hwhile system :param jobname: :return: """ #kontrola, zda existuje worker v active, a kdyz ne, tak se vlozi podle template if(self.isWorkerInActive()==False): self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised", " dont see record for worker {w} in active !! creating it ".format(w=self.workername)) self.createWorkerRecordInActive() resulttmp = self.findJobinUnassigned(jobname) if(len(resulttmp)!=1): raise NoJobFound(" given job name "+jobname+" doesnt exist") job=resulttmp[0] self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised", " job {a} will be activated now...".format(a=str(job))) if (self.createMyJobInActiveSynchronised(job)): if(self.deleteJobFromUnassignedSynchronised(job)): self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised", " job inserting to db is ok, job deleted from unassigned ") return True self.logm("MWorkerLib:moveJobFromUnassignedToActiveSynchronised", "job inserting to db failed") return False def isWorkerInTrash(self): """ will check is self.workername can be found in trash :return: true if it can be found, false if not """ result = self.meteorClient.find('trash',{"_id":self.workername}) self.logm("MWorkerLib:isWorkerInTrash", "checking, if i see my worker name in trash "+str(result)) if len(result)==1: self.logm("MWorkerLib:isWorkerInTrash", " worker with my name found in trash, erturning true") return True else: self.logm("MWorkerLib:isWorkerInTrash", "found nothing, returning False") return False def isWorkerInActive(self): """ will check is self.workername can be found in active :return: true if it can be found, false if not """ result = self.meteorClient.find('active',{"_id":self.workername}) self.logm("MWorkerLib:isWorkerInActive", "checking, if i see my worker name in active "+str(result)) if len(result)==1: self.logm("MWorkerLib:isWorkerInActive", " worker with my name found in active, erturning true") return True else: self.logm("MWorkerLib:isWorkerInActive", "found nothing, returning False") return False def createWorkerRecordInActive(self): """ will create new worker - it will not be checking if there is already worker created in active... :return: """ template={"_id":self.workername,"worker":self.workername,"workerusername":"******","jobs":[]} self.logm("MWorkerLib:createWorkerRecordInActive", "worker:" + self.workername + " is going to by added to collection active ") self.syncwaitdone = False # zacatek locku self.meteorClient.insert('active', template, callback=self.callback_synchro) res = self.syncWait() # konec locku return res def createWorkerRecordInTrash(self): """ will create new worker - it will not be checking if there is already worker created in active... :return: """ template={"_id":self.workername,"worker":self.workername,"workerusername":"******","jobs":[]} self.logm("MWorkerLib:createWorkerRecordInTrash", "worker:" + self.workername + " is going to by added to collection trash ") self.syncwaitdone = False # zacatek locku self.meteorClient.insert('trash', template, callback=self.callback_synchro) res = self.syncWait() # konec locku return res def findJobinUnassigned(self, jobname): """ will return job from unassigned by jobname this is synchron method... it will wait for ( synchron_timeout ) seconds, and return false :param job: :return: false on timeout ( synchron_timeout ) or if return is different from 1. """ return self.meteorClient.find('unassigned', {"_id": jobname}) def createMyJobInActiveSynchronised(self, job): """ this will take as input dict of job... and add it to jobs[] in proper worker... :param job: dict of job... :return: false on timeout ( synchron_timeout ) or if return is different from 1. """ template = { 'pluginname': job['pluginname'], 'jobname': job['jobname'], 'starttime': int(time.time()), # epocha 'ttl': job['expectedttl'], 'inputparams': job['inputparams'], 'progress': 0, 'result': "undefined" } self.logm("MWorkerLib:createMyJobInActive", "worker:" + self.workername + " is going to insert to active following: " + str(job)) self.syncwaitdone = False # zacatek locku self.meteorClient.update('active', {'_id': self.workername}, {'$push': {'jobs': template}}, callback=self.callback_synchro) res = self.syncWait() # konec locku return res def callback_synchro(self, error, data): self.data = data self.error = error if error: self.logm("MWorkerLib:update_callback_synchro", "worker:" + self.workername + " failed error is " + str(error)) self.syncwaitdone = True return self.logm("MWorkerLib:update_callback_synchro", "is ok. number of updates is " + str(data)) self.syncwaitdone = True def syncWait(self): """ this will wait till data of error are not empty. it will do for self.SYNCHRO_TIMEOUT seconds. then it will return False also it will check what is return value from request. if update is 0, false, othervice true """ epoch = int(time.time()) while (((int(time.time()) - epoch) < self.SYNCHRO_TIMEOUT) and (self.syncwaitdone == False)): try: time.sleep(1) self.logm("MWorkerLib:syncWait", "inside waiting cycle :") except KeyboardInterrupt: break if (self.syncwaitdone == False): # cycle was broken before timeou return False try: # zkouska, zda se updatoval aspon jeden radek if (int(self.data) == 0): # mongo changed nothing, but there was no error return False else: return True except: pass # nothing found, cykluus end on timeout return False def deleteJobFromUnassignedSynchronised(self, job): """ this will delete selected job from unassigned this is synchron method... it will wait for ( synchron_timeout ) seconds, and return false :param job: :return: false on timeout ( synchron_timeout ) or if return is different from 1. """ self.syncwaitdone = False # zacatek locku self.logm("MWorkerLib:createMyJobInActive", "worker:" + self.workername + " is going to remove job from unassigned " + str(job)) self.meteorClient.remove('unassigned', {'_id': job['_id']}, callback=self.callback_synchro) res = self.syncWait() # konec locku self.logm("MWorkerLib:createMyJobInActive", "worker:" + self.workername + " removed " + str(job)+ "result is "+str(res)) return res #########################testing def testScenario1(self): """ this is scenario 1... this will move job from unassigned to active, then from active to trash... also it will list unassigned tasks :return: self.logm("MWorkerLib:testScenario1", "start test scenario 1") self.logm("MWorkerLib:testScenario1", "moving from unassigned to active") all_posts = self.meteorClient.find('unassigned') #job = (all_posts).keys() #get first unassigned: firstUnassigned=self.meteorClient.find('unassigned')[0] ttltmp=100 #pro testovaci ucely jsem vytvoril v active workera: # db.active.insert({"_id":"localhostworker","worker":"localhostworker","workerusername":"******","jobs":[]}) template={ 'pluginname':firstUnassigned['pluginname'], 'starttime':int(time.time()), #epocha 'ttl':ttltmp, 'inputparams':firstUnassigned['inputparams'], 'progress':0, 'result':"undefined" } #insert to active: #musim pouzit id_ protoze klient rve ze kod je insecure a musi se pouzit id #s _id je dalsi problem. protoze interne mongodb pouziva objekt, ne stringu #tak bude vyhodnejsi nahradit pri vytvoreni workeru v active _id s nejakym retezcem _ worker=self.meteorClient.find_one('active',{"worker" : "localhostworker"}) #worker["workerusername"]="******" self.logm("MWorkerLib:testScenario1", "worker:"+str(worker)+" "+worker['_id']) worker1=self.meteorClient.find_one('active',{"_id":worker["_id"]}) self.logm("MWorkerLib:testScenario1", "worker:"+str(worker1)+" "+worker1['_id']) self.meteorClient.update('active',{'_id':worker['_id']},{'$push':{'jobs':template}},callback=update_callback) #self.infiniteCycle() self.logm("MWorkerLib:testScenario1", "deleting job from unassigned") self.meteorClient.remove('unassigned',{'_id':firstUnassigned['_id']},callback=remove_callback) time.sleep(5) """ job = {'_id': "asdasdsad", 'jobname': "asdasd", 'pluginname': "asdasda", 'inputparams': "assad", 'expectedttl': "100"} #otestovane a funkcni 11.2.2016: #tohle presune job s danym jmenem do active pod jmeno mistniho workera... #self.moveJobFromUnassignedToActiveSynchronised("blabla") self.moveJobFromActiveToTrash("blabla")
class MyProgram: def __init__(self): slackLog("Gate scanner started.") self.parents= {} #load parents self.client = MeteorClient('ws://chloe.asianhope.org:8080/websocket',debug=False) self.client.connect() self.client.login(METEOR_USERNAME,METEOR_PASSWORD) self.client.subscribe('cards') self.client.subscribe('scans') time.sleep(3) #give it some time to finish loading everything self.all_cards = self.client.find('cards') slackLog("Pulled records for: "+str(len(self.all_cards))+" cards") for card in self.all_cards: try: barcode = card['barcode'] name = card['name'] cardtype = card['type'] expires = card['expires'] profile = card.get('profile',barcode+".JPG") #default picture associations = card['associations'] self.parents.update({barcode:card}) except KeyError: slackLog(barcode+' has missing data',delay=True) pass # load style css for template screen = Gdk.Screen.get_default() css_provider = Gtk.CssProvider() css_provider.load_from_path('style.css') context = Gtk.StyleContext() context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER) # connect to glade teamplate self.gladefile = "cardmanager.glade" self.glade = Gtk.Builder() self.glade.add_from_file(self.gladefile) self.glade.connect_signals(self) #get window from glade self.app_window=self.glade.get_object("main_window") # Window Name in GLADE self.app_window.fullscreen() # quit app self.app_window.connect("delete-event",Gtk.main_quit) #change color of window?? #self.green = gtk.gdk.color_parse('green') #self.black = gtk.gdk.color_parse('black') #self.app_window.modify_bg(gtk.STATE_NORMAL,self.black) # get objects from glade self.header = self.glade.get_object("header") self.header_context = self.header.get_style_context() self.header_title = self.glade.get_object("header_title") self.parent_image = self.glade.get_object("img_parent") self.child_container = self.glade.get_object("grid1") self.button_search = self.glade.get_object("btn_search") self.entry = self.glade.get_object("search_input") self.pname = self.glade.get_object("lbl_pname") self.pbarcode = self.glade.get_object("lbl_pbarcode") self.pexpires = self.glade.get_object("lbl_pexpires") self.error_message = self.glade.get_object("lbl_error_message") #add event to button_search self.button_search.connect("clicked", self.search_button_clicked, "3") # display children images pixbuf = Pixbuf.new_from_file("static/logo.png") scaled_buf = pixbuf.scale_simple(CHILD_DIMENSIONS_X,CHILD_DIMENSIONS_Y,InterpType.BILINEAR) self.pickup_students = ['0']*9 #seed the list with the size we want for i in range(0,9): self.pickup_students[i] = Gtk.Image() self.pickup_students[i].set_from_pixbuf(scaled_buf) self.label=Gtk.Table(3,3,True) self.label.attach(self.pickup_students[0],0,1,0,1) self.label.attach(self.pickup_students[1],1,2,0,1) self.label.attach(self.pickup_students[2],2,3,0,1) self.label.attach(self.pickup_students[3],0,1,1,2) self.label.attach(self.pickup_students[4],1,2,1,2) self.label.attach(self.pickup_students[5],2,3,1,2) self.label.attach(self.pickup_students[6],0,1,2,3) self.label.attach(self.pickup_students[7],1,2,2,3) self.label.attach(self.pickup_students[8],2,3,2,3) self.label.set_col_spacings(10) self.label.set_row_spacings(10) # add lebel of image to container in glade self.child_container.add(self.label) # display parent picture pixbuf = Pixbuf.new_from_file("static/logo.png") scaled_buf = pixbuf.scale_simple(PARENT_DIMENSIONS_X,PARENT_DIMENSIONS_Y,InterpType.BILINEAR) self.parent_image.set_from_pixbuf(scaled_buf) # self.button_search.can_default(True) # self.button_search.grab_default() self.entry.set_activates_default(True) self.app_window.set_focus(self.entry) self.error_message.set_text("") self.app_window.show_all() return def search_button_clicked(self, widget, data=None): associations = [] self.error_message.set_text("") # remove classes in header header_class_list = self.header_context.list_classes() for class_name in header_class_list: self.header_context.remove_class(class_name) for i in range(0,9): #make sure all pictures are reset pixbuf = Pixbuf.new_from_file("static/logo.png") scaled_buf = pixbuf.scale_simple(CHILD_DIMENSIONS_X,CHILD_DIMENSIONS_Y,InterpType.BILINEAR) self.pickup_students[i].set_from_pixbuf(scaled_buf) #grab pid pid = self.entry.get_text() slackLog('Scanned card: '+pid,delay=True) #do a lookup for the name try: #get parent information #parent_card = self.client.find_one('cards', selector={'barcode': pid}) parent_card = self.parents[pid] slackLog('```'+str(parent_card)+'```',delay=True) if not parent_card: self.header_title.set_text("Invalid Card!") self.header_context.add_class('header_invalid_card') self.pname.set_text("Card Not Found!") self.pbarcode.set_text("XXXX") self.pexpires.set_text("xxxx-xx-xx") pixbuf = Pixbuf.new_from_file("static/NA.JPG") scaled_buf = pixbuf.scale_simple(PARENT_DIMENSIONS_X,PARENT_DIMENSIONS_Y,InterpType.BILINEAR) self.parent_image.set_from_pixbuf(scaled_buf) else: pname = parent_card.get('name', pid) parent_picture = parent_card.get('profile',pid+".JPG") expires = parent_card.get('expires',"Expiry not set") barcode = parent_card.get('barcode',"Barcode not set") associations = parent_card.get('associations',[]) # if card expired if expires < date.today().isoformat(): associations = [] self.header_title.set_text("Card has expired!") self.header_context.add_class('header_expired') else: def getScanCallbackFunction(error, result): # if cannot get scan, display error message if error: self.header_title.set_text('Scan failed!') self.error_message.set_text(error['message']) self.header_context.add_class('header_invalid_card') return else: # if card no scan in, add new scan if result == None: # scan in action = 'Security Scan' value = 0.00 products = [] user = METEOR_USERNAME self.client.call('scanIn',[pid,action,value,products,user],scanInCallbackFunction) # if card already scan in, update scan else: # scan out scan_id = result['_id'] self.client.call('scanOut',[scan_id],scanOutCallbackFunction) def scanInCallbackFunction(error,result): # to check if card scan-in success or error if error: self.header_title.set_text('Scan failed!') self.error_message.set_text(error['message']) self.header_context.add_class('header_invalid_card') else: self.header_title.set_text("Scan-in") self.header_context.add_class('header_scan_in') def scanOutCallbackFunction(error,result): # to check if card scan-out success or error if error: self.header_title.set_text('Scan failed!') self.error_message.set_text(error['message']) self.header_context.add_class('header_invalid_card') else: self.header_title.set_text("Scan-out") self.header_context.add_class('header_scan_out') # get scan to check if scan in or scan out self.client.call('get_scan',[pid],getScanCallbackFunction) self.pname.set_text(pname) self.pbarcode.set_text(barcode) self.pexpires.set_text(expires) # load picture try: slackLog('loading parent picture: '+str(pid),delay=True) fetchPhotosByID(parent_picture) pixbuf = Pixbuf.new_from_file("resource/"+parent_picture) scaled_buf = pixbuf.scale_simple(PARENT_DIMENSIONS_X,PARENT_DIMENSIONS_Y,InterpType.BILINEAR) self.parent_image.set_from_pixbuf(scaled_buf) except Exception as inst: slackLog("No parent picture for: "+pid,delay=True) pixbuf = Pixbuf.new_from_file("static/unknown.jpg") scaled_buf = pixbuf.scale_simple(PARENT_DIMENSIONS_X,PARENT_DIMENSIONS_Y,InterpType.BILINEAR) self.parent_image.set_from_pixbuf(scaled_buf) except KeyError: slackLog('Scanned card: '+pid+' could not be found',delay=True) #display an error self.header_title.set_text("Invalid Card!") self.header_context.add_class('header_invalid_card') self.pname.set_text("Card Not Found!") self.pbarcode.set_text("XXXX") self.pexpires.set_text("xxxx-xx-xx") pixbuf = Pixbuf.new_from_file("static/NA.JPG") scaled_buf = pixbuf.scale_simple(PARENT_DIMENSIONS_X,PARENT_DIMENSIONS_Y,InterpType.BILINEAR) self.parent_image.set_from_pixbuf(scaled_buf) #reset everything self.entry.set_text('') self.app_window.set_focus(self.entry) self.app_window.show() #try and load the studnts starting after the parents name i = 0 if(len(associations)): pool = ThreadPool(len(associations)) results = pool.map(fetchPhotosByID,associations) for sid in associations: #if the student picture exists locally, load it try: pixbuf = Pixbuf.new_from_file("resource/"+sid+".JPG") scaled_buf = pixbuf.scale_simple(CHILD_DIMENSIONS_X,CHILD_DIMENSIONS_Y,InterpType.BILINEAR) self.pickup_students[i].set_from_pixbuf(scaled_buf) #if not, load the NA picture to indicate a student w/o a picture except: print("Unexpected error:```") print sys.exc_info()[0] pixbuf = Pixbuf.new_from_file("static/NA.JPG") scaled_buf = pixbuf.scale_simple(CHILD_DIMENSIONS_X,CHILD_DIMENSIONS_Y,InterpType.BILINEAR) self.pickup_students[i].set_from_pixbuf(scaled_buf) i+=1 #clear entry box and reset focus self.entry.set_text('') self.app_window.set_focus(self.entry) self.app_window.show()