def playback(self): # This is just like PerformLine.playback, but it doesn't echo # the line when rerecording, because PostponeLine has already # echoed it. if logutils.debugLevel() >= 4: print >> sys.stderr, "Executing", self.srcline, self.line exec(self.line, sys.modules[__name__].__dict__) if logutils.debugLevel() >= 4: print >> sys.stderr, "Finished", self.srcline, self.line self.status = "done" return False
def signalLogger(obj, signal, *args): if logutils.recording() and not logutils.replaying(): try: records = findLogger(obj).record(obj, signal, *args) except logutils.GtkLoggerTopFailure, exc: if logutils.debugLevel() >= 3: print >> sys.stderr, "Can't log %s (%s): %s" \ (obj.__class__.__name__, signal, exc) except logutils.GtkLoggerException, exc: if logutils.debugLevel() >= 1: print >> sys.stderr, "Can't log %s (%s): %s" % \ (obj.__class__.__name__, signal, exc)
def playback(self): # Do NOT echo to the logfile, even if rerecording. The point # of rerecording is to allow checkpoints to be added by the # code. if checkpoint.check_checkpoint(self.comment): if logutils.debugLevel() >= 4: print >> sys.stderr, "Reached checkpoint", self.srcline self.status = "done" else: self.status = "repeating" if logutils.debugLevel() >= 4: print >> sys.stderr, "Waiting on checkpoint", self.srcline gobject.timeout_add(retrydelay, self, priority=gobject.PRIORITY_LOW) return False
def _writeline(line): global _prevline if line != _prevline or _not_redundant(line): print >> logutils.logfile(), line logutils.logfile().flush() if logutils.debugLevel() >= 2 and not logutils.replaying(): print >> sys.stderr, "//////", line _prevline = line
def playback(self): if logutils.recording(): loggers._writeline("pause" + self.delaytime) if _threaded and self.delaytime > 0: if self.status == "running": self.status = "repeating" if logutils.debugLevel() >= 4: print >> sys.stderr, self.srcline, \ "Pausing", self.delaytime, "milliseconds" gobject.timeout_add(self.delaytime, self, priority=gobject.PRIORITY_LOW) elif self.status == "repeating": if logutils.debugLevel() >= 4: print >> sys.stderr, "Done pausing", self.srcline self.status = "done" else: # not threaded, no need to wait for background tasks self.status = "done" return False
def start(self): # Install ourself as an idle callback. The callback is set to # a low priority, because we're simulating a user's mouse # clicks and keyboard events, and users are slow. If we run # at normal priority, the simulated events interfere with # normal gtk operation. if self.status == "initialized": self.status = "installed" if logutils.debugLevel() >= 4: print >> sys.stderr, "Installing", self.srcline gobject.idle_add(self, priority=gobject.PRIORITY_LOW)
def playback(self): if logutils.recording(): ## Hack opportunity: if it's necessary to modify some ## lines in existing log files, check for the lines here, ## and call loggers._writeline with the modified version. ## This will allow log files to be modified by rerecording ## them. loggers._writeline(self.line) if logutils.debugLevel() >= 4: print >> sys.stderr, "Executing", self.srcline, self.line # Exec'ing the line with an explicitly provided dictionary # allows variables created on one line to be available on a # later line. Otherwise, the variable's scope would just be # this function call, which wouldn't be very useful. exec(self.line, sys.modules[__name__].__dict__) if logutils.debugLevel() >= 4: print >> sys.stderr, "Finished", self.srcline, self.line self.status = "done" return False
def checkpoint(comment): _checkpointlock.acquire() try: if logutils.recording(): # recording print >> logutils.logfile(), "checkpoint", comment logutils.logfile().flush() if logutils.debugLevel() >= 2: print >> sys.stderr, "////// checkpoint", comment if logutils.replaying(): try: _checkpointdict[comment] += 1 except KeyError: _checkpointdict[comment] = 1 finally: _checkpointlock.release()
def checkpoint(comment): _checkpointlock.acquire() try: #print "checkpoint access attempt: %s" %comment if logutils.recording(): # recording # print "checkpoint accessed for recording: %s" %comment print >> logutils.logfile(), "checkpoint", comment if logutils.debugLevel() >= 2: print >> sys.stderr, "////// checkpoint", comment if logutils.replaying(): try: _checkpointdict[comment] += 1 #print "checkpoint accessed for replaying: %s" %comment except KeyError: _checkpointdict[comment] = 1 #print "checkpoint fail to be played: %s" %comment #if not logutils.replaying() and not logutils.recording(): #print "checkpoint access failed: %s" %comment finally: _checkpointlock.release()
if logutils.debugLevel() >= 3: print >> sys.stderr, "Can't log %s (%s): %s" \ (obj.__class__.__name__, signal, exc) except logutils.GtkLoggerException, exc: if logutils.debugLevel() >= 1: print >> sys.stderr, "Can't log %s (%s): %s" % \ (obj.__class__.__name__, signal, exc) else: if records is GtkLogger.ignore: pass elif records is not None: assert type(records) is types.ListType for record in records: _writeline(record) else: if logutils.debugLevel() >= 1: print >> sys.stderr, "No record function for", obj, signal return False # propagate events ## Some lines are logged too often. This code eliminates redundant ## lines, making the log files easier to read and faster to run. ## _redundantlines is a list of regular expression objects that match ## lines that are redundant when repeated. _redundantlines = [ # Each time a Window is created, it emits four 'configure-event' # signals, which show up as four 'resize' lines in the log. re.compile(r".*\.resize\([0-9]+, [0-9]+\)$"), # set_position lines for HPaned and VPaned widgets are generated # from their children's 'size-allocate' signals, which are
def __call__(self): # Execute our line of the gui log, *if* the previous line has # completed. Figuring out if the previous line has completed # is non-trivial, because the previous line may have emitted a # gtk signal that caused a modal dialog box to open, in which # case its "emit" call won't return until the box has closed! # *This* line contains the commands that operate the dialog # box, and must be issued even though the previous command # hasn't returned. If the previous line hasn't returned it # must have called Dialog.run or started up a new gtk main # loop, so by keeping track of gtk.main_level() and the number # of open dialogs, we can tell when it's time to execute our # line. (This is why we must redefine the Dialog class.) if self.logrunner.aborted: # The previous line raised an exception, so don't run this # line, even though it's already been installed as an idle # callback. self.status = "aborted" return False # Run this line, but only if there are no postponed lines # ready to go, and if this line is also ready. if not self.run_postponed() and self.ready(): assert self.status in ("repeating", "installed") # Add the idle callback for the next line *before* # executing our line, because we might not return # until after the next line is done! This is why we # need a separate idle callback for each line. if self.status != "repeating" and self.nextLine() is not None: self.nextLine().start() if _threaded: gtk.gdk.threads_enter() try: if self.status == "installed": self.status = "running" self.report() self.runLevel = logutils.run_level() # self.playback performs some suitable action and # returns True if the idle callback should be # repeated, and False if it shouldn't. It can also # reinstall the callback, and should set self.status # to "done" if the task is finished. try: result = self.playback() if self.nextLine() is None: self.logrunner.stop() return result except logutils.GtkLoggerTopFailure: # It's possible that the previous log line tried # to open a window, but the window hasn't actually # appeared yet. In that case, our line will have # failed with a GtkLoggerTopFailure exception. We # just want to keep trying (within reason) until # the window appears. Using checkpoints to wait # until the window is mapped makes this problem # less frequent, but doesn't make it go away # entirely. self.status = "repeating" self.ntries += 1 if self.ntries == maxtries: if logutils.debugLevel() >= 1: print >> sys.stderr, \ "Failed to find top-level widget after", \ self.ntries, "attempts." raise # Keep trying. By reinstalling ourself in the # idle callback table and returning False # (meaning, "don't repeat this callback") we move # to the back of the queue. This allows the # widget we are waiting for to appear, we hope. gobject.timeout_add(retrydelay, self, priority=gobject.PRIORITY_LOW) return False except logutils.exceptions(), exc: # Any type of exception other than GtkLoggerTopFailure # is fatal. self.status = "aborted" self.logrunner.abort() if self.logrunner.exceptHook: if not self.logrunner.exceptHook(exc, self.srcline): raise exc finally: gtk.gdk.flush() if _threaded: gtk.gdk.threads_leave() # We're still waiting for the previous line to execute. We put # ourself at the back of the execution queue (by reinstalling # and returning False) so that the previous line will run # first. if logutils.debugLevel() >= 4: print >> sys.stderr, "Reinstalling", self.srcline gobject.timeout_add(retrydelay, self, priority=gobject.PRIORITY_LOW) return False