def _show_message_in_main_thread(self, msg_fn, args): """ If running in the main thread, run the message dialog function and return its return value. If running in a non-main thread, request the message function to be called in the main thread. :param msg_fn: message dialog function to be run :type msg_fn: a function taking the same number of arguments as is the length of the args param :param args: arguments to be passed to the message dialog function :type args: any """ if threadMgr.in_main_thread(): # call the function directly return msg_fn(*args) else: # create a queue for the result returned by the function ret_queue = Queue.Queue() # request the function to be called in the main thread self._send_show_message(msg_fn, args, ret_queue) # wait and return the result from the queue return ret_queue.get()
def _call_method(*args, **kwargs): """The new body for the decorated method. """ if threadMgr.in_main_thread(): # nothing special has to be done in the main thread func(*args, **kwargs) return GLib.idle_add(_idle_method, args, kwargs)
def _call_method(*args, **kwargs): """The new body for the decorated method. If needed, it uses closure bound queue_instance variable which is valid until the reference to this method is destroyed.""" if threadMgr.in_main_thread(): # nothing special has to be done in the main thread return func(*args, **kwargs) GLib.idle_add(_idle_method, queue_instance, args, kwargs) return queue_instance.get()
def handleException(self, dump_info): """ Our own handleException method doing some additional stuff before calling the original python-meh's one. :type dump_info: an instance of the meh.DumpInfo class :see: python-meh's ExceptionHandler.handleException """ log.debug("running handleException") exception_lines = traceback.format_exception(*dump_info.exc_info) log.critical("\n".join(exception_lines)) ty = dump_info.exc_info.type value = dump_info.exc_info.value try: gi.require_version("Gtk", "3.0") from gi.repository import Gtk # XXX: Gtk stopped raising RuntimeError if it fails to # initialize. Horay! But will it stay like this? Let's be # cautious and raise the exception on our own to work in both # cases initialized = Gtk.init_check(None)[0] if not initialized: raise RuntimeError() # Attempt to grab the GUI initializing lock, do not block if not self._gui_lock.acquire(False): # the graphical interface is running, don't crash it by # running another one potentially from a different thread log.debug("Gtk running, queuing exception handler to the " "main loop") GLib.idle_add(self._main_loop_handleException, dump_info) else: log.debug("Gtk not running, starting Gtk and running " "exception handler in it") self._main_loop_handleException(dump_info) except (RuntimeError, ImportError, ValueError): log.debug("Gtk cannot be initialized") # X not running (Gtk cannot be initialized) if threadMgr.in_main_thread(): log.debug("In the main thread, running exception handler") if issubclass(ty, CmdlineError) or not self._interactive: if issubclass(ty, CmdlineError): cmdline_error_msg = _( "\nThe installation was stopped due to " "incomplete spokes detected while running " "in non-interactive cmdline mode. Since there " "cannot be any questions in cmdline mode, " "edit your kickstart file and retry " "installation.\nThe exact error message is: " "\n\n%s.\n\nThe installer will now terminate." ) % str(value) else: cmdline_error_msg = _( "\nRunning in cmdline mode, no interactive debugging " "allowed.\nThe exact error message is: " "\n\n%s.\n\nThe installer will now terminate." ) % str(value) # since there is no UI in cmdline mode and it is completely # non-interactive, we can't show a message window asking the user # to acknowledge the error; instead, print the error out and sleep # for a few seconds before exiting the installer print(cmdline_error_msg) time.sleep(10) sys.exit(1) else: print("\nAn unknown error has occured, look at the " "/tmp/anaconda-tb* file(s) for more details") # in the main thread, run exception handler self._main_loop_handleException(dump_info) else: log.debug("In a non-main thread, sending a message with " "exception data") # not in the main thread, just send message with exception # data and let message handler run the exception handler in # the main thread exc_info = dump_info.exc_info hubQ.send_exception((exc_info.type, exc_info.value, exc_info.stack))
def gtk_batch_map(action, items, args=(), pre_func=None, batch_size=1): """ Function that maps an action on items in a way that makes the action run in the main thread, but without blocking the main thread for a noticeable time. If a pre-processing function is given it is mapped on the items first before the action happens in the main thread. .. DANGER:: MUST NOT BE CALLED NOR WAITED FOR FROM THE MAIN THREAD. :param action: any action that has to be done on the items in the main thread :type action: (action_item, \\*args) -> None :param items: an iterable of items that the action should be mapped on :type items: iterable :param args: additional arguments passed to the action function :type args: tuple :param pre_func: a function that is mapped on the items before they are passed to the action function :type pre_func: item -> action_item :param batch_size: how many items should be processed in one run in the main loop :raise AssertionError: if called from the main thread :return: None """ assert(not threadMgr.in_main_thread()) def preprocess(queue_instance): if pre_func: for item in items: queue_instance.put(pre_func(item)) else: for item in items: queue_instance.put(item) queue_instance.put(TERMINATOR) def process_one_batch(arguments): (queue_instance, action, done_event) = arguments tstamp_start = time.time() tstamp = time.time() # process as many batches as user shouldn't notice while tstamp - tstamp_start < NOTICEABLE_FREEZE: for _i in range(batch_size): try: action_item = queue_instance.get_nowait() if action_item is TERMINATOR: # all items processed, tell we are finished and return done_event.set() return False else: # run action on the item action(action_item, *args) except queue.Empty: # empty queue_instance, reschedule to run later return True tstamp = time.time() # out of time but something left, reschedule to run again later return True item_queue_instance = queue.Queue() done_event = threading.Event() # we don't want to log the whole list, type and address is enough log.debug("Starting applying %s on %s", action, object.__repr__(items)) # start a thread putting preprocessed items into the queue_instance threadMgr.add(AnacondaThread(prefix="AnaGtkBatchPre", target=preprocess, args=(item_queue_instance,))) GLib.idle_add(process_one_batch, (item_queue_instance, action, done_event)) done_event.wait() log.debug("Finished applying %s on %s", action, object.__repr__(items))
def handleException(self, dump_info): """ Our own handleException method doing some additional stuff before calling the original python-meh's one. :type dump_info: an instance of the meh.DumpInfo class :see: python-meh's ExceptionHandler.handleException """ log.debug("running handleException") ty = dump_info.exc_info.type value = dump_info.exc_info.value if (issubclass(ty, blivet.errors.StorageError) and value.hardware_fault) \ or (issubclass(ty, OSError) and value.errno == errno.EIO): # hardware fault or '[Errno 5] Input/Output error' hw_error_msg = _("The installation was stopped due to what " "seems to be a problem with your hardware. " "The exact error message is:\n\n%s.\n\n " "The installer will now terminate.") % str(value) self.intf.messageWindow(_("Hardware error occured"), hw_error_msg) sys.exit(0) else: try: from gi.repository import Gtk # XXX: Gtk stopped raising RuntimeError if it fails to # initialize. Horay! But will it stay like this? Let's be # cautious and raise the exception on our own to work in both # cases initialized = Gtk.init_check(None)[0] if not initialized: raise RuntimeError() if Gtk.main_level() > 0: # main loop is running, don't crash it by running another one # potentially from a different thread log.debug("Gtk running, queuing exception handler to the " "main loop") GLib.idle_add(self.run_handleException, dump_info) else: log.debug("Gtk not running, starting Gtk and running " "exception handler in it") super(AnacondaExceptionHandler, self).handleException( dump_info) except RuntimeError: log.debug("Gtk cannot be initialized") # X not running (Gtk cannot be initialized) if threadMgr.in_main_thread(): log.debug("In the main thread, running exception handler") print "An unknown error has occured, look at the "\ "/tmp/anaconda-tb* file(s) for more details" # in the main thread, run exception handler super(AnacondaExceptionHandler, self).handleException( dump_info) else: log.debug("In a non-main thread, sending a message with " "exception data") # not in the main thread, just send message with exception # data and let message handler run the exception handler in # the main thread exc_info = dump_info.exc_info hubQ.send_exception((exc_info.type, exc_info.value, exc_info.stack))
def handleException(self, dump_info): """ Our own handleException method doing some additional stuff before calling the original python-meh's one. :type dump_info: an instance of the meh.DumpInfo class :see: python-meh's ExceptionHandler.handleException """ log.debug("running handleException") exception_lines = traceback.format_exception(*dump_info.exc_info) log.critical("\n".join(exception_lines)) ty = dump_info.exc_info.type value = dump_info.exc_info.value try: gi.require_version("Gtk", "3.0") from gi.repository import Gtk # XXX: Gtk stopped raising RuntimeError if it fails to # initialize. Horay! But will it stay like this? Let's be # cautious and raise the exception on our own to work in both # cases initialized = Gtk.init_check(None)[0] if not initialized: raise RuntimeError() # Attempt to grab the GUI initializing lock, do not block if not self._gui_lock.acquire(False): # the graphical interface is running, don't crash it by # running another one potentially from a different thread log.debug("Gtk running, queuing exception handler to the " "main loop") GLib.idle_add(self._main_loop_handleException, dump_info) else: log.debug("Gtk not running, starting Gtk and running " "exception handler in it") self._main_loop_handleException(dump_info) except (RuntimeError, ImportError, ValueError): log.debug("Gtk cannot be initialized") # X not running (Gtk cannot be initialized) if threadMgr.in_main_thread(): log.debug("In the main thread, running exception handler") if issubclass(ty, CmdlineError) or not self._interactive: if issubclass(ty, CmdlineError): cmdline_error_msg = _( "\nThe installation was stopped due to " "incomplete spokes detected while running " "in non-interactive cmdline mode. Since there " "cannot be any questions in cmdline mode, " "edit your kickstart file and retry " "installation.\nThe exact error message is: " "\n\n%s.\n\nThe installer will now terminate." ) % str(value) else: cmdline_error_msg = _( "\nRunning in cmdline mode, no interactive debugging " "allowed.\nThe exact error message is: " "\n\n%s.\n\nThe installer will now terminate." ) % str(value) # since there is no UI in cmdline mode and it is completely # non-interactive, we can't show a message window asking the user # to acknowledge the error; instead, print the error out and sleep # for a few seconds before exiting the installer print(cmdline_error_msg) time.sleep(10) sys.exit(1) else: print("\nAn unknown error has occured, look at the " "/tmp/anaconda-tb* file(s) for more details") # in the main thread, run exception handler self._main_loop_handleException(dump_info) else: log.debug("In a non-main thread, sending a message with " "exception data") # not in the main thread, just send message with exception # data and let message handler run the exception handler in # the main thread exc_info = dump_info.exc_info hubQ.send_exception( (exc_info.type, exc_info.value, exc_info.stack))
def handleException(self, dump_info): """ Our own handleException method doing some additional stuff before calling the original python-meh's one. :type dump_info: an instance of the meh.DumpInfo class :see: python-meh's ExceptionHandler.handleException """ log.debug("running handleException") exception_lines = traceback.format_exception(*dump_info.exc_info) log.debug("\n".join(exception_lines)) ty = dump_info.exc_info.type value = dump_info.exc_info.value if (issubclass(ty, blivet.errors.StorageError) and value.hardware_fault) \ or (issubclass(ty, OSError) and value.errno == errno.EIO): # hardware fault or '[Errno 5] Input/Output error' hw_error_msg = _("The installation was stopped due to what " "seems to be a problem with your hardware. " "The exact error message is:\n\n%s.\n\n " "The installer will now terminate.") % str(value) self.intf.messageWindow(_("Hardware error occured"), hw_error_msg) sys.exit(0) else: try: from gi.repository import Gtk # XXX: Gtk stopped raising RuntimeError if it fails to # initialize. Horay! But will it stay like this? Let's be # cautious and raise the exception on our own to work in both # cases initialized = Gtk.init_check(None)[0] if not initialized: raise RuntimeError() if Gtk.main_level() > 0: # main loop is running, don't crash it by running another one # potentially from a different thread log.debug("Gtk running, queuing exception handler to the " "main loop") GLib.idle_add(self.run_handleException, dump_info) else: log.debug("Gtk not running, starting Gtk and running " "exception handler in it") super(AnacondaExceptionHandler, self).handleException( dump_info) except (RuntimeError, ImportError): log.debug("Gtk cannot be initialized") # X not running (Gtk cannot be initialized) if threadMgr.in_main_thread(): log.debug("In the main thread, running exception handler") if (issubclass (ty, CmdlineError)): cmdline_error_msg = _("\nThe installation was stopped due to " "incomplete spokes detected while running " "in non-interactive cmdline mode. Since there " "can not be any questions in cmdline mode, " "edit your kickstart file and retry " "installation.\nThe exact error message is: " "\n\n%s.\n\nThe installer will now terminate.") % str(value) # since there is no UI in cmdline mode and it is completely # non-interactive, we can't show a message window asking the user # to acknowledge the error; instead, print the error out and sleep # for a few seconds before exiting the installer print(cmdline_error_msg) time.sleep(10) sys.exit(0) else: print("\nAn unknown error has occured, look at the " "/tmp/anaconda-tb* file(s) for more details") # in the main thread, run exception handler super(AnacondaExceptionHandler, self).handleException( dump_info) else: log.debug("In a non-main thread, sending a message with " "exception data") # not in the main thread, just send message with exception # data and let message handler run the exception handler in # the main thread exc_info = dump_info.exc_info hubQ.send_exception((exc_info.type, exc_info.value, exc_info.stack))
def handleException(self, dump_info): """ Our own handleException method doing some additional stuff before calling the original python-meh's one. :type dump_info: an instance of the meh.DumpInfo class :see: python-meh's ExceptionHandler.handleException """ log.debug("running handleException") ty = dump_info.exc_info.type value = dump_info.exc_info.value if (issubclass(ty, blivet.errors.StorageError) and value.hardware_fault) \ or (issubclass(ty, OSError) and value.errno == errno.EIO): # hardware fault or '[Errno 5] Input/Output error' hw_error_msg = _("The installation was stopped due to what " "seems to be a problem with your hardware. " "The exact error message is:\n\n%s.\n\n " "The installer will now terminate.") % str(value) self.intf.messageWindow(_("Hardware error occured"), hw_error_msg) sys.exit(0) else: try: from gi.repository import Gtk # XXX: Gtk stopped raising RuntimeError if it fails to # initialize. Horay! But will it stay like this? Let's be # cautious and raise the exception on our own to work in both # cases initialized = Gtk.init_check(None)[0] if not initialized: raise RuntimeError() if Gtk.main_level() > 0: # main loop is running, don't crash it by running another one # potentially from a different thread log.debug("Gtk running, queuing exception handler to the " "main loop") GLib.idle_add(self.run_handleException, dump_info) else: log.debug("Gtk not running, starting Gtk and running " "exception handler in it") super(AnacondaExceptionHandler, self).handleException(dump_info) except RuntimeError: log.debug("Gtk cannot be initialized") # X not running (Gtk cannot be initialized) if threadMgr.in_main_thread(): log.debug("In the main thread, running exception handler") print "An unknown error has occured, look at the "\ "/tmp/anaconda-tb* file(s) for more details" # in the main thread, run exception handler super(AnacondaExceptionHandler, self).handleException(dump_info) else: log.debug("In a non-main thread, sending a message with " "exception data") # not in the main thread, just send message with exception # data and let message handler run the exception handler in # the main thread exc_info = dump_info.exc_info hubQ.send_exception( (exc_info.type, exc_info.value, exc_info.stack))
def handleException(self, dump_info): """ Our own handleException method doing some additional stuff before calling the original python-meh's one. :type dump_info: an instance of the meh.DumpInfo class :see: python-meh's ExceptionHandler.handleException """ log.debug("running handleException") ty = dump_info.exc_info.type value = dump_info.exc_info.value if issubclass(ty, blivet.errors.StorageError) and value.hardware_fault: hw_error_msg = _("The installation was stopped due to what " "seems to be a problem with your hardware. " "The exact error message is:\n\n%s.\n\n " "The installer will now terminate.") % str(value) self.intf.messageWindow(_("Hardware error occured"), hw_error_msg) sys.exit(0) else: try: # pylint: disable-msg=E0611 from gi.repository import Gtk # XXX: Gtk stopped raising RuntimeError if it fails to # initialize. Horay! But will it stay like this? Let's be # cautious and raise the exception on our own to work in both # cases (initialized, args) = Gtk.init_check(None) if not initialized: raise RuntimeError() if Gtk.main_level() > 0: # main loop is running, don't crash it by running another one # potentially from a different thread log.debug("Gtk running, queuing exception handler to the " "main loop") GLib.idle_add(self.run_handleException, dump_info) else: log.debug("Gtk not running, starting Gtk and running " "exception handler in it") super(AnacondaExceptionHandler, self).handleException(dump_info) except RuntimeError: log.debug("Gtk cannot be initialized") # X not running (Gtk cannot be initialized) if threadMgr.in_main_thread(): log.debug("In the main thread, running exception handler") if (issubclass(ty, CmdlineError)): cmdline_error_msg = _( "\nThe installation was stopped due to an " "error which occurred while running in " "non-interactive cmdline mode. Since there can " "not be any questions in cmdline mode, edit " "your kickstart file and retry installation. " "\nThe exact error message is: \n\n%s. \n\nThe " "installer will now terminate.") % str(value) # since there is no UI in cmdline mode and it is completely # non-interactive, we can't show a message window asking the user # to acknowledge the error; instead, print the error out and sleep # for a few seconds before exiting the installer print(cmdline_error_msg) time.sleep(180) sys.exit() else: print "An unknown error has occured, look at the "\ "/tmp/anaconda-tb* file(s) for more details" # in the main thread, run exception handler super(AnacondaExceptionHandler, self).handleException(dump_info) else: log.debug("In a non-main thread, sending a message with " "exception data") # not in the main thread, just send message with exception # data and let message handler run the exception handler in # the main thread exc_info = dump_info.exc_info hubQ.send_exception( (exc_info.type, exc_info.value, exc_info.stack))
def gtk_batch_map(action, items, args=(), pre_func=None, batch_size=1): """ Function that maps an action on items in a way that makes the action run in the main thread, but without blocking the main thread for a noticeable time. If a pre-processing function is given it is mapped on the items first before the action happens in the main thread. .. DANGER:: MUST NOT BE CALLED NOR WAITED FOR FROM THE MAIN THREAD. :param action: any action that has to be done on the items in the main thread :type action: (action_item, \\*args) -> None :param items: an iterable of items that the action should be mapped on :type items: iterable :param args: additional arguments passed to the action function :type args: tuple :param pre_func: a function that is mapped on the items before they are passed to the action function :type pre_func: item -> action_item :param batch_size: how many items should be processed in one run in the main loop :raise AssertionError: if called from the main thread :return: None """ assert (not threadMgr.in_main_thread()) def preprocess(queue_instance): if pre_func: for item in items: queue_instance.put(pre_func(item)) else: for item in items: queue_instance.put(item) queue_instance.put(TERMINATOR) def process_one_batch(arguments): (queue_instance, action, done_event) = arguments tstamp_start = time.time() tstamp = time.time() # process as many batches as user shouldn't notice while tstamp - tstamp_start < NOTICEABLE_FREEZE: for _i in range(batch_size): try: action_item = queue_instance.get_nowait() if action_item is TERMINATOR: # all items processed, tell we are finished and return done_event.set() return False else: # run action on the item action(action_item, *args) except queue.Empty: # empty queue_instance, reschedule to run later return True tstamp = time.time() # out of time but something left, reschedule to run again later return True item_queue_instance = queue.Queue() done_event = threading.Event() # we don't want to log the whole list, type and address is enough log.debug("Starting applying %s on %s", action, object.__repr__(items)) # start a thread putting preprocessed items into the queue_instance threadMgr.add( AnacondaThread(prefix="AnaGtkBatchPre", target=preprocess, args=(item_queue_instance, ))) GLib.idle_add(process_one_batch, (item_queue_instance, action, done_event)) done_event.wait() log.debug("Finished applying %s on %s", action, object.__repr__(items))