[Zope-Checkins] CVS: Zope3/utilities - unittestgui.py:1.3

Martijn Pieters mj@zope.com
Wed, 26 Jun 2002 16:20:05 -0400


Update of /cvs-repository/Zope3/utilities
In directory cvs.zope.org:/tmp/cvs-serv22315/utilities

Modified Files:
	unittestgui.py 
Log Message:
- Add statusbar feedback when having clicked the Start button, indicating
  that the GUI is importing the tests; this can take a while.

- Add a -m commandline option for a minimal GUI; only show the progressbar.

  Double-Clicking the progress bar starts the tests. The bar shows number of
  tests run, total number of tests, and if there are any, the number of
  errors and failures. The command line option only makes sense when you
  specify the test module on the command line.


=== Zope3/utilities/unittestgui.py 1.2 => 1.3 ===
             self.__rollbackImporter.rollbackImports()
         self.__rollbackImporter = RollbackImporter()
+        self.notifyStartImport()
         try:
             test = unittest.defaultTestLoader.loadTestsFromNames(
                                 COMMA_SPACE.split( testName ) )
@@ -121,6 +122,10 @@
 
     # Required callbacks
 
+    def notifyStartImport(self):
+        "Override to display a message that imports are about to start"
+        pass
+
     def notifyRunning(self):
         "Override to set GUI in 'running' mode, enabling 'stop' button etc."
         pass
@@ -218,11 +223,12 @@
 class TkTestRunner(BaseGUITestRunner):
     """An implementation of BaseGUITestRunner using Tkinter.
     """
-    def initGUI(self, root, initialTestName):
+    def initGUI(self, root, initialTestName, minimal=0):
         """Set up the GUI inside the given root window. The test name entry
         field will be pre-filled with the given initialTestName.
         """
         self.root = root
+        self.minimal = minimal
         # Set up values that will be tied to widgets
         self.suiteNameVar = tk.StringVar()
         self.suiteNameVar.set(initialTestName)
@@ -244,14 +250,16 @@
         """
         # Status bar
         statusFrame = tk.Frame(self.top, relief=tk.SUNKEN, borderwidth=2)
-        statusFrame.pack(anchor=tk.SW, fill=tk.X, side=tk.BOTTOM)
+        if not self.minimal:
+            statusFrame.pack(anchor=tk.SW, fill=tk.X, side=tk.BOTTOM)
         tk.Label(statusFrame, textvariable=self.statusVar).pack(side=tk.LEFT)
 
         # Area to enter name of test to run
         leftFrame = tk.Frame(self.top, borderwidth=3)
         leftFrame.pack(fill=tk.BOTH, side=tk.LEFT, anchor=tk.NW, expand=1)
         suiteNameFrame = tk.Frame(leftFrame, borderwidth=3)
-        suiteNameFrame.pack(fill=tk.X)
+        if not self.minimal:
+            suiteNameFrame.pack(fill=tk.X)
         tk.Label(suiteNameFrame, text="Enter test name:").pack(side=tk.LEFT)
         e = tk.Entry(suiteNameFrame, textvariable=self.suiteNameVar, width=80)
         e.pack(side=tk.LEFT, fill=tk.X, expand=1)
@@ -261,14 +269,20 @@
         # Progress bar
         progressFrame = tk.Frame(leftFrame, relief=tk.GROOVE, borderwidth=2)
         progressFrame.pack(fill=tk.X, expand=0, anchor=tk.NW)
-        tk.Label(progressFrame, text="Progress:").pack(anchor=tk.W)
+        if not self.minimal:
+            tk.Label(progressFrame, text="Progress:").pack(anchor=tk.W)
         self.progressBar = ProgressBar(progressFrame, relief=tk.SUNKEN,
                                        borderwidth=2)
+        if self.minimal:
+            self.progressBar.setProgressFraction(0.0, '0/0')
         self.progressBar.pack(fill=tk.X, expand=1)
+        self.progressBar.bind('<Double-Button-1>',
+            lambda e, self=self: self.runClicked())
 
         # Area with buttons to start/stop tests and quit
         buttonFrame = tk.Frame(self.top, borderwidth=3)
-        buttonFrame.pack(side=tk.LEFT, anchor=tk.NW, fill=tk.Y)
+        if not self.minimal:
+            buttonFrame.pack(side=tk.LEFT, anchor=tk.NW, fill=tk.Y)
         self.stopGoButton = tk.Button(buttonFrame, text="Start",
                                       command=self.runClicked)
         self.stopGoButton.pack(fill=tk.X)
@@ -280,19 +294,22 @@
                   command=self.showHelpDialog).pack(side=tk.BOTTOM, fill=tk.X)
 
         # Area with labels reporting results
-        for label, var in (('Run:', self.runCountVar),
-                           ('Failures:', self.failCountVar),
-                           ('Errors:', self.errorCountVar),
-                           ('Remaining:', self.remainingCountVar)):
-            tk.Label(progressFrame, text=label).pack(side=tk.LEFT)
-            tk.Label(progressFrame, textvariable=var,
-                     foreground="blue").pack(side=tk.LEFT, fill=tk.X,
-                                             expand=1, anchor=tk.W)
+        if not self.minimal:
+            for label, var in (('Run:', self.runCountVar),
+                            ('Failures:', self.failCountVar),
+                            ('Errors:', self.errorCountVar),
+                            ('Remaining:', self.remainingCountVar)):
+                tk.Label(progressFrame, text=label).pack(side=tk.LEFT)
+                tk.Label(progressFrame, textvariable=var,
+                        foreground="blue").pack(side=tk.LEFT, fill=tk.X,
+                                                expand=1, anchor=tk.W)
 
         # List box showing errors and failures
-        tk.Label(leftFrame, text="Failures and errors:").pack(anchor=tk.W)
+        if not self.minimal:
+            tk.Label(leftFrame, text="Failures and errors:").pack(anchor=tk.W)
         listFrame = tk.Frame(leftFrame, relief=tk.SUNKEN, borderwidth=2)
-        listFrame.pack(fill=tk.BOTH, anchor=tk.NW, expand=1)
+        if not self.minimal:
+            listFrame.pack(fill=tk.BOTH, anchor=tk.NW, expand=1)
         self.errorListbox = tk.Listbox(listFrame, foreground='red',
                                        selectmode=tk.SINGLE,
                                        selectborderwidth=0)
@@ -305,9 +322,11 @@
         self.errorListbox.configure(yscrollcommand=listScroll.set)
 
         # List box showing warnings
-        tk.Label(leftFrame, text="Warnings:").pack(anchor=tk.W)
+        if not self.minimal:
+            tk.Label(leftFrame, text="Warnings:").pack(anchor=tk.W)
         warnFrame = tk.Frame(leftFrame, relief=tk.SUNKEN, borderwidth=2)
-        warnFrame.pack(fill=tk.BOTH, anchor=tk.NW, expand=1)
+        if not self.minimal:
+            warnFrame.pack(fill=tk.BOTH, anchor=tk.NW, expand=1)
         self.warningListbox = tk.Listbox(warnFrame, foreground='black',
                                        selectmode=tk.SINGLE,
                                        selectborderwidth=0)
@@ -327,6 +346,13 @@
         tkMessageBox.showerror(parent=self.root, title=title,
                                message=message)
 
+    def notifyStartImport(self):
+        if self.minimal:
+            self.progressBar.setProgressFraction(0.0, 'Importing...')
+        else:
+            self.statusVar.set("Importing tests...")
+        self.top.update_idletasks()
+
     def notifyRunning(self):
         self.runCountVar.set(0)
         self.failCountVar.set(0)
@@ -341,7 +367,8 @@
         #Stopping seems not to work, so simply disable the start button
         #self.stopGoButton.config(command=self.stopClicked, text="Stop")
         self.stopGoButton.config(state=tk.DISABLED)
-        self.progressBar.setProgressFraction(0.0)
+        progressText = self.minimal and ('0/%d' % self.totalTests) or None
+        self.progressBar.setProgressFraction(0.0, progressText)
         self.top.update_idletasks()
 
     def notifyStopped(self):
@@ -350,7 +377,10 @@
         self.statusVar.set("Idle")
 
     def notifyTestStarted(self, test):
-        self.statusVar.set(str(test))
+        test = str(test)
+        if len(test) > 60:
+            test = test[:30] + ' ... ' + test[-25:]
+        self.statusVar.set(test)
         self.top.update_idletasks()
 
     def notifyWarning(self, msg, tb_str):
@@ -369,10 +399,19 @@
 
     def notifyTestFinished(self, test):
         self.remainingCountVar.set(self.remainingCountVar.get() - 1)
-        self.runCountVar.set(1 + self.runCountVar.get())
-        fractionDone = float(self.runCountVar.get())/float(self.totalTests)
+        run = self.runCountVar.get() + 1
+        self.runCountVar.set(run)
+        fractionDone = float(run)/float(self.totalTests)
+        progressText = ''
+        if self.minimal:
+            progressText = '%d/%d' % (run, self.totalTests)
+        if self.failCountVar.get():
+            progressText += ' (F: %d)' % self.failCountVar.get()
+        if self.errorCountVar.get():
+            progressText += ' (E: %d)' % self.errorCountVar.get()
         fillColor = len(self.errorInfo) and "red" or "green"
-        self.progressBar.setProgressFraction(fractionDone, fillColor)
+        self.progressBar.setProgressFraction(fractionDone, progressText,
+            fillColor)
 
     def showAboutDialog(self):
         tkMessageBox.showinfo(parent=self.root, title="About PyUnit",
@@ -443,11 +482,32 @@
         self.canvas.bind('<Configure>', self.paint)
         self.setProgressFraction(0.0)
 
-    def setProgressFraction(self, fraction, color='blue'):
+    def setProgressFraction(self, fraction, label='', color='blue'):
         self.fraction = fraction
+        self.label = label
         self.color = color
         self.paint()
         self.canvas.update_idletasks()
+
+    def bind(self, sequence=None, callback=None, add=None):
+        "Bindings should be propagated to the contained canvas."
+        tk.Frame.bind(self, sequence, callback, add)
+        self.canvas.bind(sequence, callback, add)
+        
+    def unbind(self, sequence):
+        "Bindings should be propagated to the contained canvas."
+        tk.Frame.unbind(self, sequence)
+        self.canvas.unbind(sequence)
+        
+    def bind_class(self, className, sequence=None, callback=None, add=None):
+        "Bindings should be propagated to the contained canvas."
+        tk.Frame.bind_class(self, className, sequence, callback, add)
+        self.canvas.bind_class(className, sequence, callback, add)
+        
+    def unbind_class(self, className, sequence):
+        "Bindings should be propagated to the contained canvas."
+        tk.Frame.bind_class(self, className, sequence)
+        self.canvas.bind_class(className, sequence)
         
     def paint(self, *args):
         totalWidth = self.canvas.winfo_width()
@@ -457,22 +517,28 @@
         if self.text is not None: self.canvas.delete(self.text)
         self.rect = self.canvas.create_rectangle(0, 0, width, height,
                                                  fill=self.color)
-        percentString = "%3.0f%%" % (100.0 * self.fraction)
+        if self.label:
+            label = self.label
+        else:
+            label = "%3.0f%%" % (100.0 * self.fraction)
         self.text = self.canvas.create_text(totalWidth/2, height/2,
                                             anchor=tk.CENTER,
-                                            text=percentString)
+                                            text=label)
 
-def main(initialTestName=""):
+def main(initialTestName="", minimal=0):
     root = tk.Tk()
     root.title("PyUnit")
-    runner = TkTestRunner(root, initialTestName)
+    runner = TkTestRunner(root, initialTestName, minimal)
     root.protocol('WM_DELETE_WINDOW', root.quit)
     root.mainloop()
 
 
 if __name__ == '__main__':
     import sys
-    if len(sys.argv) == 2:
-        main(sys.argv[1])
+    import getopt
+    opts, args = getopt.getopt(sys.argv[1:], 'm')
+    minimal = ('-m', '') in opts
+    if args:
+        main(args[0], minimal=minimal)
     else:
         main()