def run_later(self, command, *args): if wx.IsMainThread(): command(*args) else: wx.CallAfter(command, *args)
def wrapper(*args, **kwargs): if wx.IsMainThread(): func(*args, **kwargs) else: wx.CallAfter(lambda args, kwargs: func(*args, **kwargs), args, kwargs)
def __OnInteract(self, event): assert wx.IsMainThread() try: event.OnProcess(self.__win) finally: event._threadEvt.set() # pylint: disable=protected-access
def update_text(self, text): if not wx.IsMainThread(): wx.CallAfter(self.update_text_gui, text + '\n') else: self.update_text_gui(text + '\n')
def on_hidden_message(self, hidden_conversations): assert wx.IsMainThread() self.set_hidden_messages(len(hidden_conversations))
def _display_error_dialog( frame, exc, pipeline, message=None, tb=None, continue_only=False, remote_exc_info=None, ): """Display an error dialog, returning an indication of whether to continue frame - parent frame for application exc - exception that caused the error pipeline - currently executing pipeline message - message to display tb - traceback continue_only - show "continue" option, only remote_exc_info - None (the default) for exceptions in the current process. For remote processes: (exc_name, exc_message, traceback_text, filename, line_number, remote_event_queue) Returns either ED_STOP or ED_CONTINUE indicating how to handle. """ import wx assert wx.IsMainThread(frame), "Can only display errors from WX thread." if remote_exc_info: from_subprocess = True exc_name, exc_message, traceback_text, filename, line_number, remote_debug_callback = ( remote_exc_info) if message is None: message = exc_message else: from_subprocess = False if message is None: message = str(exc) if tb is None: traceback_text = traceback.format_exc() tb = sys.exc_info()[2] else: traceback_text = "".join( traceback.format_exception(type(exc), exc, tb)) # find the place where this error occurred, and if we've already # reported it, don't do so again (instead, just log it to the # console), to prevent the UI from becoming unusable. filename, line_number, _, _ = traceback.extract_tb(tb)[-1] if (filename, line_number) in previously_seen_error_locations: if from_subprocess: logging.root.error( "Previously displayed remote exception:\n%s\n%s", exc_name, traceback_text, ) else: logging.root.error( "Previously displayed uncaught exception:", exc_info=(type(exc), exc, tb), ) return ED_CONTINUE dialog = wx.Dialog(frame, title="Pipeline error", style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) sizer = wx.BoxSizer(wx.VERTICAL) dialog.SetSizer(sizer) if continue_only: qc_msg = "Encountered error while processing." else: qc_msg = ("Encountered error while processing. " "Do you want to stop processing?") question_control = wx.StaticText(dialog, -1, qc_msg) question_control.Font = wx.Font( int(dialog.GetFont().GetPointSize() * 5 / 4), dialog.GetFont().GetFamily(), dialog.GetFont().GetStyle(), wx.FONTWEIGHT_BOLD, ) sizer.Add(question_control, 0, wx.EXPAND | wx.ALL, 5) error_box = wx.BoxSizer(wx.HORIZONTAL) message_control = wx.StaticText(dialog, -1, message) error_box.Add(message_control, 1, wx.EXPAND | wx.RIGHT, 5) sizer.Add(error_box, 1, wx.EXPAND | wx.ALL, 5) aux_button_box = wx.BoxSizer(wx.VERTICAL) error_box.Add(aux_button_box, 0, wx.EXPAND) # # Handle show details button # details_button = wx.Button(dialog, -1, "Details...") details_button.SetToolTip("Show error details") aux_button_box.Add(details_button, 0, wx.EXPAND | wx.BOTTOM, 5) details_on = [False] def on_details(event): if not details_on[0]: message_control.SetLabel("%s\n%s" % (message, traceback_text)) message_control.Refresh() details_button.SetLabel("Hide details...") details_button.Refresh() dialog.Fit() details_on[0] = True else: message_control.SetLabel(message) message_control.Refresh() details_button.SetLabel("Details...") details_button.Refresh() dialog.Fit() details_on[0] = False dialog.Bind(wx.EVT_BUTTON, on_details, details_button) # # Handle copy button # copy_button = wx.Button(dialog, -1, "Copy to clipboard") copy_button.SetToolTip("Copy error to clipboard") aux_button_box.Add(copy_button, 0, wx.EXPAND | wx.BOTTOM, 5) def on_copy(event): if wx.TheClipboard.Open(): try: wx.TheClipboard.Clear() wx.TheClipboard.SetData(wx.TextDataObject(traceback_text)) wx.TheClipboard.Flush() finally: wx.TheClipboard.Close() dialog.Bind(wx.EVT_BUTTON, on_copy, copy_button) # # Handle pdb button # if ((tb or remote_exc_info) is not None) and (not hasattr(sys, "frozen") or os.getenv("CELLPROFILER_DEBUG")): if not from_subprocess: pdb_button = wx.Button(dialog, -1, "Debug in pdb...") pdb_button.SetToolTip("Debug in python's pdb on the console") aux_button_box.Add(pdb_button, 0, wx.EXPAND | wx.BOTTOM, 5) def handle_pdb(event): import pdb pdb.post_mortem(tb) # This level of interest seems to indicate the user might # want to debug this error if it occurs again. if (filename, line_number) in previously_seen_error_locations: previously_seen_error_locations.remove( (filename, line_number)) else: pdb_button = wx.Button(dialog, -1, "Debug remotely...") pdb_button.SetToolTip("Debug remotely in pdb via telnet") aux_button_box.Add(pdb_button, 0, wx.EXPAND | wx.BOTTOM, 5) def handle_pdb(event): if not remote_debug_callback(): # The user has told us that remote debugging has gone wonky pdb_button.Enable(False) # This level of interest seems to indicate the user might # want to debug this error if it occurs again. if (filename, line_number) in previously_seen_error_locations: previously_seen_error_locations.remove( (filename, line_number)) dialog.Bind(wx.EVT_BUTTON, handle_pdb, pdb_button) dont_show_exception_checkbox = wx.CheckBox( dialog, label="Don't show this error again") dont_show_exception_checkbox.SetValue(False) sizer.Add(dont_show_exception_checkbox, 0, wx.ALIGN_LEFT | wx.ALL, 5) # # Handle the "stop" button being pressed # result = [None] def on_stop(event): dialog.SetReturnCode(wx.YES) result[0] = ED_STOP dialog.Close() event.Skip() stop_button = wx.Button(dialog, label="Stop processing...") dialog.Bind(wx.EVT_BUTTON, on_stop, stop_button) # # Handle the "continue" button being pressed # def on_continue(event): result[0] = ED_CONTINUE dialog.SetReturnCode(wx.NO) dialog.Close() event.Skip() continue_button = wx.Button(dialog, label="Continue processing...") dialog.Bind(wx.EVT_BUTTON, on_continue, continue_button) # # Handle report button # def handle_report(event): on_report(event, dialog, traceback_text, pipeline) report_button = wx.Button(dialog, label="Send report...") report_button.SetToolTip("Upload error report to the CellProfiler Project") dialog.Bind(wx.EVT_BUTTON, handle_report, report_button) # # Handle "Skip Image" button being pressed # def on_skip(event): result[0] = ED_SKIP dialog.Close() event.Skip() skip_button = wx.Button(dialog, label="Skip Image, Continue Pipeline") dialog.Bind(wx.EVT_BUTTON, on_skip, skip_button) button_sizer = wx.BoxSizer(wx.HORIZONTAL) button_sizer.Add((2, 2)) button_sizer.Add(stop_button) button_sizer.Add((5, 5), proportion=1) button_sizer.Add(continue_button) button_sizer.Add((5, 5), proportion=1) button_sizer.Add(report_button) button_sizer.Add((5, 5), proportion=1) button_sizer.Add(skip_button) button_sizer.Add((2, 2)) if continue_only: button_sizer.Hide(stop_button) button_sizer.Hide(skip_button) sizer.Add(button_sizer, 0, wx.EXPAND | wx.ALL, 4) dialog.Fit() dialog.ShowModal() if dont_show_exception_checkbox.IsChecked(): previously_seen_error_locations.add((filename, line_number)) return result[0]
def syncwrap(*args, **kwargs): if wx.IsMainThread(): return self.func(*args, **kwargs) else: sync = Synchronizer(func, *args, **kwargs) return sync.Run()
def refresh_display(self): if not wx.IsMainThread(): wx.CallAfter(self.refresh_in_ui) else: self.refresh_in_ui()