code: 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()
      ), "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]
  
file_path: CellProfiler/src/frontend/cellprofiler/gui/errordialog.py
imports: import functools
  import io
  import logging
  import os
  import platform
  import sys
  import traceback
  import urllib
  import urllib.parse
  import urllib.request
  from urllib.error import HTTPError, URLError
  from urllib.request import urlopen
  from cellprofiler_core.preferences import get_headless
label_desc: Use image node_id 3 for calling a global function with example usage: _display_error_dialog(frame, exc, pipeline, message, tb, continue_only, remote_exc_info) and returns: result, ED_CONTINUE