import sys, traceback, threading EXIT_SUCCESS=0 EXIT_ERROR=1 def info(message): # print info to sys.stderr because it isn’t really output, just debug information print("INFO: "+str(message), file=sys.stderr) traceback.print_stack() def warn(message, is_exception=False): print("WARNING: "+str(message), file=sys.stderr) if is_exception: traceback.print_exc() else: traceback.print_stack() def error(message, is_exception=True, handle_gracefully=True): print("ERROR: "+str(message), file=sys.stderr) if is_exception: traceback.print_exc() else: traceback.print_stack() if handle_gracefully: pass else: sys.exit(EXIT_ERROR) # easy way to communicate across events #TODO: make thread safe class Communication: def __init__(self): self.lock = threading.Lock() self.__messages = {} # send a message tagged with name and containing content, adds to the beginning of the list of messages with the same tag by default, a function to run as an additional action can be provided def send(self, name, content, reverse_order=True, additional_action=None): self.lock.acquire() if name in self.__messages: if reverse_order: self.__messages[name] = [content] + self.__messages[name] else: self.__messages[name] = self.__messages[name] + [content] else: self.__messages[name] = [content] if additional_action == None: pass else: additional_action() self.lock.release() # get the content of the first message tagged with name, removes the returned message by default def get(self, name, remove=True): self.lock.acquire() if name in self.__messages and len(self.__messages[name])>0: if remove: content = self.__messages[name].pop(0) if len(self.__messages[name])==0: del self.__messages[name] self.lock.release() return content else: self.lock.release() return self.__messages[name][0] else: self.lock.release() return None # get the contents for all messages tagged with name def get_all(self, name, clear=False): self.lock.acquire() if name in self.__messages and len(self.__messages[name])>0: contents = self.__messages[name] if clear: del self.__messages[name] self.lock.release() return contents else: self.lock.release() return None # deletes all messages tagged with name def clear(self, name): self.lock.acquire() if name in self.__messages: del self.__messages[name] self.lock.release() def __del__(self): if len(self.__messages)>0: warn("__messages not empty upon destruction of Communication object:\n"+str(self.__messages))