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.Thread_IsMain(), "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 previously_seen_error_locations.add((filename, line_number)) dialog = wx.Dialog(frame, title="Pipeline error", style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) sizer = wx.BoxSizer(wx.VERTICAL) dialog.SetSizer(sizer) question_control = wx.StaticText( dialog, -1, "Encountered error while processing. " "Do you want to stop processing?") question_control.Font = wx.Font(int(dialog.Font.GetPointSize() * 5 / 4), dialog.Font.GetFamily(), dialog.Font.GetStyle(), wx.FONTWEIGHT_BOLD) sizer.Add(question_control, 0, wx.EXPAND | wx.ALL, 5) error_control = wx.StaticBox(dialog, -1, "Error:") error_box = wx.StaticBoxSizer(error_control, 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.SetToolTipString("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.Label = "%s\n%s" % (message, traceback_text) message_control.Refresh() details_button.Label = "Hide details..." details_button.Refresh() dialog.Fit() details_on[0] = True else: message_control.Label = message message_control.Refresh() details_button.Label = "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.SetToolTipString("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.SetToolTipString("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.SetToolTipString("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) # # 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.SetToolTipString( "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() return result[0]
def write(self, string): if not wx.Thread_IsMain(): # Aquire the GUI mutex before making GUI calls. Mutex is released # when locker is deleted at the end of this function. # # TODO: This should be updated to use wx.CallAfter similarly to how # PyOnDemandOutputWindow.write was so it is not necessary # to get the gui mutex locker = wx.MutexGuiLocker() if self.Enabled: if self.f: self.f.write(string) self.f.flush() move = 1 if (hasattr(self, "text") and self.text is not None and self.text.GetInsertionPoint() != self.text.GetLastPosition()): move = 0 if not self.frame: self.frame = wx.Frame(self.parent, -1, self.title, size=(450, 300), style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE) self.text = wx.TextCtrl(self.frame, -1, "", style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH) self.frame.sb = _MyStatusBar( self.frame, callbacks=[ self.DisableOutput, self.CloseFile, self.OpenNewFile ], useopenbutton=hasattr(self, "nofile")) self.frame.SetStatusBar(self.frame.sb) self.frame.Show(True) self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow) if hasattr(self, "nofile"): self.text.AppendText( "Please close this window (or select the " "'Dismiss' button below) when desired. By " "default all messages written to this window " "will NOT be written to a file--you " "may change this by selecting 'Open New File' " "below, allowing you to select a " "new file...\n\n") else: tempfile.tempdir = self.dir filename = '' try: self.f = tempfile.NamedTemporaryFile(mode='w', delete=False) filename = os.path.abspath(self.f.name) self.frame.sb.SetStatusText( "File '%s' opened..." % filename, 0) except EnvironmentError: self.frame.sb.SetStatusText( "File creation failed " "(filename '%s')..." % filename, 0) self.text.AppendText( "Please close this window (or select the " "'Dismiss' button below) when desired. By " "default all messages written to this window " "will also be written to the file '%s'--you " "may close this file by selecting 'Close " "File' below, whereupon this button will be " "replaced with one allowing you to select a " "new file...\n\n" % filename) self.text.AppendText(string) if move: self.text.ShowPosition(self.text.GetLastPosition()) if not hasattr(self, "no__debug__"): for m in sys.modules.values(): if m is not None: # and "__debug__" in m.__dict__: m.__dict__["__debug__"] = 1 if hasattr(self, "othermenu") and self.othermenu is not None: i = self.othermenu.FindMenuItem(self.menuname, self.disableitem) self.othermenu.Enable(i, 1) i = self.othermenu.FindMenuItem(self.menuname, self.enableitem) self.othermenu.Enable(i, 0)
def maybeCallAfter(func, *args, **kw): if wx.Thread_IsMain(): func(*args, **kw) else: wx.CallAfter(func, *args, **kw)
def __check_thread(self): if __debug__ and not wx.Thread_IsMain(): print >> sys.stderr, "EmbeddedPlayer: __check_thread thread", currentThread( ).getName(), "is NOT MainThread" print_stack()
def startDownload(self, torrentfilename=None, destdir=None, infohash=None, tdef=None, cmdline=False, vodmode=False, hops=0, selectedFiles=None, hidden=False): self._logger.debug(u"startDownload: %s %s %s %s %s", torrentfilename, destdir, tdef, vodmode, selectedFiles) # TODO(lipu): remove the assertions after it becomes stable if infohash is not None: assert isinstance(infohash, str), "infohash type: %s" % type(infohash) assert len(infohash) == 20, "infohash length is not 20: %s, %s" % ( len(infohash), infohash) # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file. # so if we have tdef, infohash and torrent_file will be ignored, and so on. if tdef is None: if infohash is not None: # try to get the torrent from torrent_store if the infohash is provided torrent_data = self.utility.session.get_collected_torrent( infohash) if torrent_data is not None: # use this torrent data for downloading tdef = TorrentDef.load_from_memory(torrent_data) if tdef is None: assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given" # try to get the torrent from the given torrent file torrent_data = fix_torrent(torrentfilename) if torrent_data is None: # show error message: could not open torrent file dlg = wx.MessageBox( self, "Could not open torrent file %s" % torrentfilename, "Error", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return tdef = TorrentDef.load_from_memory(torrent_data) assert tdef is not None, "tdef MUST not be None after loading torrent" try: d = self.utility.session.get_download(tdef.get_infohash()) if d: new_trackers = list( set(tdef.get_trackers_as_single_tuple()) - set(d.get_def().get_trackers_as_single_tuple())) if not new_trackers: raise DuplicateDownloadException() else: @forceWxThread def do_gui(): # Show update tracker dialog dialog = wx.MessageDialog( None, 'This torrent is already being downloaded. Do you wish to load the trackers from it?', 'Tribler', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if dialog.ShowModal() == wx.ID_YES: # Update trackers self.utility.session.update_trackers( tdef.get_infohash(), new_trackers) dialog.Destroy() do_gui() return defaultDLConfig = DefaultDownloadStartupConfig.getInstance() dscfg = defaultDLConfig.copy() cancelDownload = False useDefault = not self.utility.read_config('showsaveas') safe_seeding = self.utility.read_config( 'default_safeseeding_enabled') if not useDefault and not destdir: defaultname = tdef.get_name_as_unicode( ) if tdef.is_multifile_torrent() else None if wx.Thread_IsMain(): dlg = SaveAs(None, tdef, dscfg.get_dest_dir(), defaultname, selectedFiles) dlg.CenterOnParent() if isinstance(tdef, TorrentDefNoMetainfo): # Correct for the smaller size of the dialog if there is no metainfo center_pos = dlg.GetPosition() center_pos[1] -= 150 dlg.SetPosition(center_pos) if dlg.ShowModal() == wx.ID_OK: # If the dialog has collected a torrent, use the new tdef tdef = dlg.GetCollected() or tdef if tdef and tdef.is_multifile_torrent(): selectedFiles = dlg.GetSelectedFiles() destdir = dlg.GetPath() # Anonymity over exit nodes or hidden services safe_seeding = dlg.UseSafeSeeding() if dlg.UseTunnels(): hops = self.utility.read_config( 'default_number_hops') else: cancelDownload = True dlg.Destroy() else: raise Exception("cannot create dialog, not on wx thread") # use default setup else: if useDefault: if self.utility.read_config('default_anonymity_enabled'): # only load default anonymous level if we use default settings hops = self.utility.read_config('default_number_hops') else: hops = 0 if hops > 0: if not tdef: raise Exception( 'Currently only torrents can be downloaded in anonymous mode' ) dscfg.set_hops(hops) dscfg.set_safe_seeding(safe_seeding) if not cancelDownload: if destdir is not None: dscfg.set_dest_dir(destdir) if selectedFiles and len(selectedFiles) == 1: # we should filter files to see if they are all playable videofiles = selectedFiles elif tdef and not selectedFiles: videofiles = tdef.get_files(exts=videoextdefaults) else: videofiles = [] # disable vodmode if no videofiles, unless we still need to collect the torrent if vodmode and len(videofiles) == 0 and ( not tdef or not isinstance(tdef, TorrentDefNoMetainfo)): vodmode = False if vodmode: self._logger.info( 'MainFrame: startDownload: Starting in VOD mode') result = self.utility.session.start_download_from_tdef( tdef, dscfg) self.guiUtility.library_manager.playTorrent( tdef.get_infohash(), videofiles[0] if len(videofiles) == 1 else None) else: if selectedFiles: dscfg.set_selected_files(selectedFiles) self._logger.debug( 'MainFrame: startDownload: Starting in DL mode') result = self.utility.session.start_download_from_tdef( tdef, dscfg, hidden=hidden) if result and not hidden: self.show_saved(tdef) return result except DuplicateDownloadException as e: # If there is something on the cmdline, all other torrents start # in STOPPED state. Restart if cmdline: dlist = self.utility.session.get_downloads() for d in dlist: if d.get_def().get_infohash() == tdef.get_infohash(): d.restart() break if wx.Thread_IsMain(): # show nice warning dialog dlg = wx.MessageDialog( None, "You are already downloading this torrent, see the Downloads section.", "Duplicate download", wx.OK | wx.ICON_ERROR) result = dlg.ShowModal() dlg.Destroy() else: print_exc() self.onWarning(e) except Exception as e: print_exc() self.onWarning(e) return None
def callafterwrap(*args, **kwargs): if wx.Thread_IsMain(): return funct(*args, **kwargs) else: wx.CallAfter(funct, *args, **kwargs)
def alive(): return True class Server(Thread): def run(self): server = SimpleXMLRPCServer(("localhost", 8000), allow_none=True) server.register_introspection_functions() server.register_function(plot) server.register_function(alive) print "Listening on port 8000..." server.serve_forever() server = Server() server.start() app = wx.GetApp() assert app is not None assert wx.Thread_IsMain() evtloop = wx.EventLoop() ea = wx.EventLoopActivator(evtloop) while 1: gui_lock.acquire() while evtloop.Pending(): evtloop.Dispatch() app.ProcessIdle() gui_lock.release() gui_lock.acquire() gui_lock.release() sleep(0.001)
def write(self, text): if not wx.Thread_IsMain(): wx.CallAfter(self._do_write, text) else: self._do_write(text)
def new_guithread_function(*args, **kwargs): if wx.Thread_IsMain(): return function(*args, **kwargs) else: wx.CallAfter(function, *args, **kwargs)
def syncwrap( *args, **kwargs ): if wx.Thread_IsMain(): return self.func( *args, **kwargs ) else: sync = Synchronizer( func, *args, **kwargs ) return sync.Run()