def wait_for_exit(self, abortHandler, pollFunction = None): """ Wait for the process to exit (sleeping by 0.05 seconds in a loop). Calls pollFunction each time around the loop if it is specified. Return its exitcode. Call this only after the process was successfully started using self.start() or self.launch(). """ abortPressCount = 0 while (not self.state() == QProcess.NotRunning): if (abortHandler): pc = abortHandler.getPressCount() if (pc > abortPressCount): abortPressCount = pc if (abortPressCount > 1): self.terminate() else: self.kill() env.call_qApp_processEvents() #bruce 050908 replaced qApp.processEvents() #k is this required for us to get the slot calls for stdout / stderr ? # I don't know, but we want it even if not. if (pollFunction): pollFunction() time.sleep(0.05) if (abortHandler): abortHandler.finish() return self.exitCode()
def wait_for_exit(self, abortHandler, pollFunction=None): """ Wait for the process to exit (sleeping by 0.05 seconds in a loop). Calls pollFunction each time around the loop if it is specified. Return its exitcode. Call this only after the process was successfully started using self.start() or self.launch(). """ abortPressCount = 0 while (not self.state() == QProcess.NotRunning): if (abortHandler): pc = abortHandler.getPressCount() if (pc > abortPressCount): abortPressCount = pc if (abortPressCount > 1): self.terminate() else: self.kill() env.call_qApp_processEvents( ) #bruce 050908 replaced qApp.processEvents() #k is this required for us to get the slot calls for stdout / stderr ? # I don't know, but we want it even if not. if (pollFunction): pollFunction() time.sleep(0.05) if (abortHandler): abortHandler.finish() return self.exitCode()
def gl_update_duration(self, new_part=False): """ Redraw GLPane and update the repaint duration variable <self._repaint_duration> used by animateToView() to compute the proper number of animation frames. Redraws the GLPane twice if <new_part> is True and only saves the repaint duration of the second redraw. This is needed in the case of drawing a newly opened part, which takes much longer to draw the first time than the second (or thereafter). """ # The first redraw of a new part takes much longer than the second redraw. if new_part: self.gl_update() env.call_qApp_processEvents() # Required! self._repaint_start_time = time.time() self.gl_update() env.call_qApp_processEvents( ) # This forces the GLPane to update before executing the next gl_update(). self._repaint_end_time = time.time() self._repaint_duration = max( MIN_REPAINT_TIME, self._repaint_end_time - self._repaint_start_time) # _last_few_repaint_times is currently unused. May need it later. Mark 060116. # (bruce 080912: disabling it. if we revive it, something needs to initialize it to [].) ## self._last_few_repaint_times.append( self._repaint_duration) ## self._last_few_repaint_times = self._last_few_repaint_times[-5:] # keep at most the last five times ##if new_part: ## print "new part, repaint duration = ", self._repaint_duration ##else: ## print "repaint duration = ", self._repaint_duration return
def gl_update_duration(self, new_part = False): """ Redraw GLPane and update the repaint duration variable <self._repaint_duration> used by animateToView() to compute the proper number of animation frames. Redraws the GLPane twice if <new_part> is True and only saves the repaint duration of the second redraw. This is needed in the case of drawing a newly opened part, which takes much longer to draw the first time than the second (or thereafter). """ # The first redraw of a new part takes much longer than the second redraw. if new_part: self.gl_update() env.call_qApp_processEvents() # Required! self._repaint_start_time = time.time() self.gl_update() env.call_qApp_processEvents() # This forces the GLPane to update before executing the next gl_update(). self._repaint_end_time = time.time() self._repaint_duration = max(MIN_REPAINT_TIME, self._repaint_end_time - self._repaint_start_time) # _last_few_repaint_times is currently unused. May need it later. Mark 060116. # (bruce 080912: disabling it. if we revive it, something needs to initialize it to [].) ## self._last_few_repaint_times.append( self._repaint_duration) ## self._last_few_repaint_times = self._last_few_repaint_times[-5:] # keep at most the last five times ##if new_part: ## print "new part, repaint duration = ", self._repaint_duration ##else: ## print "repaint duration = ", self._repaint_duration return
def show_progressbar_and_stop_button(self, progressReporter, cmdname="<unknown command>", showElapsedTime=False): """ Display the statusbar's progressbar and stop button, and update it based on calls to the progressReporter. When the progressReporter indicates completion, hide the progressbar and stop button and return 0. If the user first presses the Stop button on the statusbar, hide the progressbar and stop button and return 1. Parameters: progressReporter - See potential implementations below. cmdname - name of command (used in some messages and in abort button tooltip) showElapsedTime - if True, display duration (in seconds) below progress bar Return value: 0 if file reached desired size, 1 if user hit abort button. """ updateInterval = 0.1 # seconds startTime = time.time() elapsedTime = 0 displayedElapsedTime = 0 ###e the following is WRONG if there is more than one task at a time... [bruce 060106 comment] self.progressBar.reset() self.progressBar.setMaximum(progressReporter.getMaxProgress()) self.progressBar.setValue(0) self.progressBar.show() abortHandler = AbortHandler(self, cmdname) # Main loop while progressReporter.notDoneYet(): self.progressBar.setValue(progressReporter.getProgress()) env.call_qApp_processEvents() # Process queued events (e.g. clicking Abort button, # but could be anything -- no modal dialog involved anymore). if showElapsedTime: elapsedTime = int(time.time() - startTime) if elapsedTime != displayedElapsedTime: displayedElapsedTime = elapsedTime env.history.progress_msg("Elapsed Time: " + hhmmss_str(displayedElapsedTime)) if abortHandler.getPressCount() > 0: env.history.statusbar_msg("Aborted.") abortHandler.finish() return 1 time.sleep(updateInterval) # Take a rest # End of Main loop (this only runs if it ended without being aborted) self.progressBar.setValue(progressReporter.getMaxProgress()) time.sleep(updateInterval) # Give the progress bar a moment to show 100% env.history.statusbar_msg("Done.") abortHandler.finish() return 0
def launchProgressDialog(self): """ """ stime = time.time() self.show() while 1: env.call_qApp_processEvents() if self.Rejected: break duration = time.time() - stime elapmsg = "Elapsed Time: " + hhmmss_str(int(duration)) self.msgLabel2.setText(elapmsg) time.sleep(0.01) return
def _debug_do_benchmark(self): # simple graphics benchmark, piotr 080311 from time import clock from utilities.debug import profile print "Entering graphics benchmark. Drawing 100 frames... please wait." win = self._debug_win self.win.resize(1024,768) # resize the window to a constant size self.win.glpane.paintGL() # draw once just to make sure the GL context is current # piotr 080405 env.call_qApp_processEvents() # make sure all events were processed tm0 = clock() profile(self._draw_hundred_frames, self, None) tm1 = clock() print "Benchmark complete. FPS = ", 100.0/(tm1-tm0)
def _debug_do_benchmark(self): # simple graphics benchmark, piotr 080311 from time import clock from utilities.debug import profile print "Entering graphics benchmark. Drawing 100 frames... please wait." win = self._debug_win self.win.resize(1024, 768) # resize the window to a constant size self.win.glpane.paintGL() # draw once just to make sure the GL context is current # piotr 080405 env.call_qApp_processEvents() # make sure all events were processed tm0 = clock() profile(self._draw_hundred_frames, self, None) tm1 = clock() print "Benchmark complete. FPS = ", 100.0 / (tm1 - tm0)
def _debug_do_benchmark(self): # simple graphics benchmark, piotr 080311 from time import clock print "Entering graphics benchmark. Drawing 100 frames... please wait." win = self._debug_win self.win.resize(1024, 768) # resize the window to a constant size self.win.glpane.paintGL() # draw once just to make sure the GL context is current # piotr 080405 # [BUG: the right way is gl_update -- direct call of paintGL won't # always work, context might not be current -- bruce 090305 comment] env.call_qApp_processEvents() # make sure all events were processed tm0 = clock() profile_single_call_if_enabled(self._draw_hundred_frames, self, None) tm1 = clock() print "Benchmark complete. FPS = ", 100.0 / (tm1 - tm0) return
def _debug_do_benchmark(self): # simple graphics benchmark, piotr 080311 from time import clock print "Entering graphics benchmark. Drawing 100 frames... please wait." win = self._debug_win self.win.resize(1024,768) # resize the window to a constant size self.win.glpane.paintGL() # draw once just to make sure the GL context is current # piotr 080405 # [BUG: the right way is gl_update -- direct call of paintGL won't # always work, context might not be current -- bruce 090305 comment] env.call_qApp_processEvents() # make sure all events were processed tm0 = clock() profile_single_call_if_enabled(self._draw_hundred_frames, self, None) tm1 = clock() print "Benchmark complete. FPS = ", 100.0 / (tm1 - tm0) return
def _launch_pcgamess(self): """ Run PC GAMESS (Windows only). PC GAMESS creates 2 output files: - the DAT file, called "PUNCH", is written to the directory from which PC GAMESS is started. This is why we chdir to the Gamess temp directory before we run PC GAMESS. - the OUT file (aka the log file), which we name jigname.out. Returns: 0 = Success 1 = Cancelled 2 = Failed """ oldir = os.getcwd() # Save current directory jobDir = os.path.dirname(self.job_batfile) os.chdir(jobDir) # Change directory to the GAMESS temp directory. ## print "Current directory is: ", jobDir DATfile = os.path.join(jobDir, "PUNCH") if os.path.exists(DATfile): # Remove any previous DAT (PUNCH) file. print "run_pcgamess: Removing DAT file: ", DATfile os.remove(DATfile) # Hours wasted testing this undocumented tripe. Here's the deal: When using spawnv # on Windows, any args that might have spaces must be delimited by double quotes. # Mark 050530. #program = "\"" + self.job_batfile + "\"" #args = [program, ] # Here's the infuriating part. The 2nd arg to spawnv cannot have double quotes, but the # first arg in args (the program name) must have the double quotes if there is a space in # self.gms_program. #print "program = ", program #print "Spawnv args are %r" % (args,) # this %r remains (see above) #os.spawnv(os.P_WAIT, self.job_batfile, args) arg_list = ['-i', self.job_inputfile, '-o', self.job_outputfile] args = QStringList() for s in arg_list: args.append(str(s)) process = QProcess() process.start(self.server.program, args) # Blocks for n millisconds until the process has started and started() # signal is emitted. Returns true if the process was started successfullly. if not process.waitForStarted(2000): print "The process can't be started." return 2 progressDialog = self.showProgress() progressDialog.show() i = 55 pInc = True while process.state() == QProcess.Running: env.call_qApp_processEvents() #bruce 050908 replaced qApp.processEvents() if progressDialog.wasCanceled(): process.kill() os.chdir(oldir) return 1 # Job cancelled. progressDialog.setValue(i) if pInc: if i < 75: i += 1 else: pInc = False else: if i > 55: i -= 1 else: pInc = True # Do sth here time.sleep(0.05) if not process.state() == QProcess.Running: break progressDialog.setValue(100) progressDialog.accept() os.chdir(oldir) self.gamessJig.outputfile = self.job_outputfile return 0 # Success
def show_progressbar_and_stop_button(self, progressReporter, cmdname="<unknown command>", showElapsedTime=False): """ Display the statusbar's progressbar and stop button, and update it based on calls to the progressReporter. When the progressReporter indicates completion, hide the progressbar and stop button and return 0. If the user first presses the Stop button on the statusbar, hide the progressbar and stop button and return 1. Parameters: progressReporter - See potential implementations below. cmdname - name of command (used in some messages and in abort button tooltip) showElapsedTime - if True, display duration (in seconds) below progress bar Return value: 0 if file reached desired size, 1 if user hit abort button. """ updateInterval = .1 # seconds startTime = time.time() elapsedTime = 0 displayedElapsedTime = 0 ###e the following is WRONG if there is more than one task at a time... [bruce 060106 comment] self.progressBar.reset() self.progressBar.setMaximum(progressReporter.getMaxProgress()) self.progressBar.setValue(0) self.progressBar.show() abortHandler = AbortHandler(self, cmdname) # Main loop while progressReporter.notDoneYet(): self.progressBar.setValue(progressReporter.getProgress()) env.call_qApp_processEvents() # Process queued events (e.g. clicking Abort button, # but could be anything -- no modal dialog involved anymore). if showElapsedTime: elapsedTime = int(time.time() - startTime) if (elapsedTime != displayedElapsedTime): displayedElapsedTime = elapsedTime env.history.progress_msg("Elapsed Time: " + hhmmss_str(displayedElapsedTime)) # note: it's intentional that this doesn't directly call # self._f_progress_msg. [bruce 081229 comment] if abortHandler.getPressCount() > 0: env.history.statusbar_msg("Aborted.") abortHandler.finish() return 1 time.sleep(updateInterval) # Take a rest # End of Main loop (this only runs if it ended without being aborted) self.progressBar.setValue(progressReporter.getMaxProgress()) time.sleep( updateInterval) # Give the progress bar a moment to show 100% env.history.statusbar_msg("Done.") abortHandler.finish() return 0
def _launch_pcgamess(self): """ Run PC GAMESS (Windows only). PC GAMESS creates 2 output files: - the DAT file, called "PUNCH", is written to the directory from which PC GAMESS is started. This is why we chdir to the Gamess temp directory before we run PC GAMESS. - the OUT file (aka the log file), which we name jigname.out. Returns: 0 = Success 1 = Cancelled 2 = Failed """ oldir = os.getcwd() # Save current directory jobDir = os.path.dirname(self.job_batfile) os.chdir(jobDir) # Change directory to the GAMESS temp directory. ## print "Current directory is: ", jobDir DATfile = os.path.join(jobDir, "PUNCH") if os.path.exists(DATfile): # Remove any previous DAT (PUNCH) file. print "run_pcgamess: Removing DAT file: ", DATfile os.remove(DATfile) # Hours wasted testing this undocumented tripe. Here's the deal: When using spawnv # on Windows, any args that might have spaces must be delimited by double quotes. # Mark 050530. #program = "\"" + self.job_batfile + "\"" #args = [program, ] # Here's the infuriating part. The 2nd arg to spawnv cannot have double quotes, but the # first arg in args (the program name) must have the double quotes if there is a space in # self.gms_program. #print "program = ", program #print "Spawnv args are %r" % (args,) # this %r remains (see above) #os.spawnv(os.P_WAIT, self.job_batfile, args) arg_list = ['-i', self.job_inputfile, '-o', self.job_outputfile] args = QStringList() for s in arg_list: args.append(str(s)) process = QProcess() process.start(self.server.program, args) # Blocks for n millisconds until the process has started and started() # signal is emitted. Returns true if the process was started successfullly. if not process.waitForStarted(2000): print "The process can't be started." return 2 progressDialog = self.showProgress() progressDialog.show() i = 55 pInc = True while process.state() == QProcess.Running: env.call_qApp_processEvents( ) #bruce 050908 replaced qApp.processEvents() if progressDialog.wasCanceled(): process.kill() os.chdir(oldir) return 1 # Job cancelled. progressDialog.setValue(i) if pInc: if i < 75: i += 1 else: pInc = False else: if i > 55: i -= 1 else: pInc = True # Do sth here time.sleep(0.05) if not process.state() == QProcess.Running: break progressDialog.setValue(100) progressDialog.accept() os.chdir(oldir) self.gamessJig.outputfile = self.job_outputfile return 0 # Success
def launch_povray_or_megapov( win, info, povray_ini): #bruce 060707/11 revised this extensively for Mac A8 """ Try to launch POV-Ray or MegaPOV, as specified in <info> (as returned from decode_povray_prefs, assumed already checked), on the given <povray_ini> file (which should already exist), and running in the directory of that file (this is required, since it may contain relative pathnames). <win> must be the main window object (used for .glpane.is_animating). Returns (errorcode, errortext), where errorcode is one of the following: ###k 0 = successful 8 = POV-Ray or MegaPOV failed for an unknown reason. """ (program_nickname, program_path, include_dir) = info #e rename this arg renderer_info? exit = '' program = program_path if sys.platform == 'win32': program = "\"" + program + "\"" # Double quotes needed by Windows. Mark 060602. if program_nickname == 'POV-Ray': exit = "/EXIT" # Later we'll cd to the POV-Ray's INI file directory and use tmp_ini in the POV-Ray command-line. # This helps us get around POV-Ray's I/O Restrictions. Mark 060529. workdir, tmp_ini = os.path.split(povray_ini) # Render scene. try: args = [tmp_ini] if exit: args += [exit] if env.debug(): ## use env.history.message(_graymsg(msg)) ? print "debug: Launching %s: \n" % program_nickname,\ "working directory=",workdir,"\n program_path=", program_path, "\n args are %r" % (args,) arguments = QStringList() for arg in args: if arg != "": arguments.append(arg) from processes.Process import Process p = Process() #bruce 060707: this doesn't take advantage of anything not in QProcess, # unless it matters that it reads and discards stdout/stderr # (eg so large output would not block -- unlikely that this matters). # It doesn't echo stdout/stderr. See also blabout/blaberr in other files. Maybe fix this? ###@@@ p.setWorkingDirectory(workdir) p.start(program, arguments) # Put up hourglass cursor to indicate we are busy. Restore the cursor below. Mark 060621. QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) win.glpane.is_animating = True # This disables selection [do you mean highlighting? #k] while rendering the image. import time msg = "Rendering image" while p.state() == QProcess.Running: # Display a message on the status bar that POV-Ray/MegaPOV is rendering. # I'd much rather display a progressbar and stop button by monitoring the size of the output file. # This would require the output file to be written in PPM or BMP format, but not PNG format, since # I don't believe a PNG's final filesize can be predicted. # Check out monitor_progress_by_file_growth() in runSim.py, which does this. [mark] time.sleep(0.25) env.history.statusbar_msg(msg) env.call_qApp_processEvents() if 1: # Update the statusbar message while rendering. if len( msg ) > 40: #bruce changed 100 -> 40 in case of short statusbar msg = "Rendering image" else: #msg = msg + "." msg += "." except: #bruce 060707 moved print_compact_traceback earlier, and its import to toplevel (after Windows A8, before Linux/Mac A8) print_compact_traceback("exception in launch_povray_or_megapov(): ") QApplication.restoreOverrideCursor() win.glpane.is_animating = False return 8, "%s failed for an unknown reason." % program_nickname #bruce 060707 moved the following outside the above try clause, and revised it (after Windows A8, before Linux/Mac A8) QApplication.restoreOverrideCursor() # Restore the cursor. Mark 060621. ## env.history.statusbar_msg("Rendering finished!") # this is wrong if it was not a normal exit. [bruce 060707 removed it] win.glpane.is_animating = False if 1: #bruce 060707 added this (after Windows A8, before Linux/Mac A8): # set an appropriate exitcode and msg if p.exitStatus() == QProcess.NormalExit: exitcode = p.exitStatus() if not exitcode: msg = "Rendering finished!" else: msg = "Rendering program had exitcode %r" % exitcode # e.g. 126 for Mac failure; same as shell exitcode, which says "cannot execute binary file"; # but /usr/bin/open helps, so we'll try that above (but not in this commit, which is just to # improve error reporting). ###@@@ # [bruce 060707] else: exitcode = p.exitStatus() exitcode = -1 msg = "Abnormal exit (or failure to launch)" if exitcode or env.debug(): print msg env.history.statusbar_msg(msg) ## if env.debug(): ## env.history.message(_graymsg(msg)) # not needed, caller prints it if exitcode: return 8, "Error: " + msg # this breaks the convention of the other error returns pass # Display image in separate window here. [Actually I think this is done in the caller -- bruce 060707 comment] return 0, "Rendering finished" # from launch_povray_or_megapov
def launch_povray_or_megapov(win, info, povray_ini): #bruce 060707/11 revised this extensively for Mac A8 """ Try to launch POV-Ray or MegaPOV, as specified in <info> (as returned from decode_povray_prefs, assumed already checked), on the given <povray_ini> file (which should already exist), and running in the directory of that file (this is required, since it may contain relative pathnames). <win> must be the main window object (used for .glpane.is_animating). Returns (errorcode, errortext), where errorcode is one of the following: ###k 0 = successful 8 = POV-Ray or MegaPOV failed for an unknown reason. """ (program_nickname, program_path, include_dir) = info #e rename this arg renderer_info? exit = '' program = program_path if sys.platform == 'win32': program = "\""+program+"\"" # Double quotes needed by Windows. Mark 060602. if program_nickname == 'POV-Ray': exit = "/EXIT" # Later we'll cd to the POV-Ray's INI file directory and use tmp_ini in the POV-Ray command-line. # This helps us get around POV-Ray's I/O Restrictions. Mark 060529. workdir, tmp_ini = os.path.split(povray_ini) # Render scene. try: args = [tmp_ini] if exit: args += [exit] if env.debug(): ## use env.history.message(_graymsg(msg)) ? print "debug: Launching %s: \n" % program_nickname,\ "working directory=",workdir,"\n program_path=", program_path, "\n args are %r" % (args,) arguments = QStringList() for arg in args: if arg != "": arguments.append(arg) from processes.Process import Process p = Process() #bruce 060707: this doesn't take advantage of anything not in QProcess, # unless it matters that it reads and discards stdout/stderr # (eg so large output would not block -- unlikely that this matters). # It doesn't echo stdout/stderr. See also blabout/blaberr in other files. Maybe fix this? ###@@@ p.setWorkingDirectory(workdir) p.start(program, arguments) # Put up hourglass cursor to indicate we are busy. Restore the cursor below. Mark 060621. QApplication.setOverrideCursor( QCursor(Qt.WaitCursor) ) win.glpane.is_animating = True # This disables selection [do you mean highlighting? #k] while rendering the image. import time msg = "Rendering image" while p.state() == QProcess.Running: # Display a message on the status bar that POV-Ray/MegaPOV is rendering. # I'd much rather display a progressbar and stop button by monitoring the size of the output file. # This would require the output file to be written in PPM or BMP format, but not PNG format, since # I don't believe a PNG's final filesize can be predicted. # Check out monitor_progress_by_file_growth() in runSim.py, which does this. [mark] time.sleep(0.25) env.history.statusbar_msg(msg) env.call_qApp_processEvents() if 1: # Update the statusbar message while rendering. if len(msg) > 40: #bruce changed 100 -> 40 in case of short statusbar msg = "Rendering image" else: #msg = msg + "." msg += "." except: #bruce 060707 moved print_compact_traceback earlier, and its import to toplevel (after Windows A8, before Linux/Mac A8) print_compact_traceback( "exception in launch_povray_or_megapov(): " ) QApplication.restoreOverrideCursor() win.glpane.is_animating = False return 8, "%s failed for an unknown reason." % program_nickname #bruce 060707 moved the following outside the above try clause, and revised it (after Windows A8, before Linux/Mac A8) QApplication.restoreOverrideCursor() # Restore the cursor. Mark 060621. ## env.history.statusbar_msg("Rendering finished!") # this is wrong if it was not a normal exit. [bruce 060707 removed it] win.glpane.is_animating = False if 1: #bruce 060707 added this (after Windows A8, before Linux/Mac A8): # set an appropriate exitcode and msg if p.exitStatus() == QProcess.NormalExit: exitcode = p.exitStatus() if not exitcode: msg = "Rendering finished!" else: msg = "Rendering program had exitcode %r" % exitcode # e.g. 126 for Mac failure; same as shell exitcode, which says "cannot execute binary file"; # but /usr/bin/open helps, so we'll try that above (but not in this commit, which is just to # improve error reporting). ###@@@ # [bruce 060707] else: exitcode = p.exitStatus() exitcode = -1 msg = "Abnormal exit (or failure to launch)" if exitcode or env.debug(): print msg env.history.statusbar_msg(msg) ## if env.debug(): ## env.history.message(_graymsg(msg)) # not needed, caller prints it if exitcode: return 8, "Error: " + msg # this breaks the convention of the other error returns pass # Display image in separate window here. [Actually I think this is done in the caller -- bruce 060707 comment] return 0, "Rendering finished" # from launch_povray_or_megapov