Example #1
0
 def run_later(self, command, *args):
     if wx.IsMainThread():
         command(*args)
     else:
         wx.CallAfter(command, *args)
Example #2
0
 def wrapper(*args, **kwargs):
     if wx.IsMainThread():
         func(*args, **kwargs)
     else:
         wx.CallAfter(lambda args, kwargs: func(*args, **kwargs), args, kwargs)
Example #3
0
 def __OnInteract(self, event):
     assert wx.IsMainThread()
     try:
         event.OnProcess(self.__win)
     finally:
         event._threadEvt.set()  # pylint: disable=protected-access
Example #4
0
 def update_text(self, text):
     if not wx.IsMainThread():
         wx.CallAfter(self.update_text_gui, text + '\n')
     else:
         self.update_text_gui(text + '\n')
Example #5
0
 def on_hidden_message(self, hidden_conversations):
     assert wx.IsMainThread()
     self.set_hidden_messages(len(hidden_conversations))
Example #6
0
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]
Example #7
0
 def syncwrap(*args, **kwargs):
     if wx.IsMainThread():
         return self.func(*args, **kwargs)
     else:
         sync = Synchronizer(func, *args, **kwargs)
         return sync.Run()
Example #8
0
 def refresh_display(self):
     if not wx.IsMainThread():
         wx.CallAfter(self.refresh_in_ui)
     else:
         self.refresh_in_ui()