[Zope-Checkins] CVS: Zope3/utilities - license_check.py:1.2 unittestgui.py:1.2 ExtensionBuilder.py:1.5 FS.py:1.9 bbb.py:1.15 check_catalog.py:1.5 fixbbbts.py:1.3 load_site.py:1.10 requestprofiler.py:1.17 testrunner.py:1.26
Jim Fulton
jim@zope.com
Mon, 10 Jun 2002 19:30:19 -0400
Update of /cvs-repository/Zope3/utilities
In directory cvs.zope.org:/tmp/cvs-serv20468/utilities
Modified Files:
ExtensionBuilder.py FS.py bbb.py check_catalog.py fixbbbts.py
load_site.py requestprofiler.py testrunner.py
Added Files:
license_check.py unittestgui.py
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.
=== Zope3/utilities/license_check.py 1.1 => 1.2 ===
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+# small script to check all Python files for a correct header,
+# specifically a presence of the correct license text from
+# $ZOPE_HOME/zpl.py
+
+usage = """\
+%s looks for the presence of the right license text in
+all Python files. It can be run in different modes.
+
+usage: %s -c|-w|--undo [-s, -v, --nobackup] path
+
+-c : put a license text at the top of each file
+-w : print the names of files without a license text
+-s : strict checking. If this option is not set, only handle files
+ without any form of license text. If set, an exact license text
+ needs to be present
+-v : be verbose
+-h : Print this help
+
+-l=path : Give the absolute path to zpl.py
+
+--nobackup : Do not generate backup files
+--include_init : Process also the __init__.py files
+--undo : Rename the backup files to the original files, mainly for
+ testing.
+
+path : If not given start in the current directory.
+
+Example: To put a license in all files
+license_check.py -c -v -s --nobackup --include_init
+"""
+
+
+import os, fnmatch, sys
+import re
+
+class ZLicenseCheckError(Exception):
+ fname = ''
+ msg = ''
+ def __init__(self, msg, fname):
+ self.msg = msg
+ self.fname = fname
+ Exception.__init__(self, msg, fname)
+
+ def __str__(self):
+ return self.msg
+
+class GlobDirectoryWalker:
+ # a forward iterator that traverses a directory tree
+ # snippet posted by Frederik Lundh in c.l.p.
+ #
+ def __init__(self, directory, pattern="*"):
+ self.stack = [directory]
+ self.pattern = pattern
+ self.files = []
+ self.index = 0
+
+
+ def __getitem__(self, index):
+ while 1:
+ try:
+ file = self.files[self.index]
+ self.index = self.index + 1
+ except IndexError:
+ # pop next directory from stack
+ self.directory = self.stack.pop()
+ self.files = os.listdir(self.directory)
+ self.index = 0
+ else:
+ # got a filename
+ fullname = os.path.join(self.directory, file)
+ if os.path.isdir(fullname) and not os.path.islink(fullname):
+ self.stack.append(fullname)
+ if fnmatch.fnmatch(file, self.pattern):
+ return fullname
+
+class HeaderCheck:
+ """Make the header of a given file have a license text."""
+
+ def __init__(self, fname, zpl, verbose=0, backup=1):
+ """\
+ fname -> name of the checked file
+ zpl -> instance of ZPL, class representing the license
+ """
+ self.fname = fname
+ self.header_length = 700
+ self.license = zpl.license_text
+ self.verbose = verbose
+ self.backup = backup
+
+
+ def get_header(self):
+ """Get a number if lines of the file. The number is an
+ instance attribute"""
+ header = open(self.fname,'r').read(self.header_length)
+ return header
+
+
+ def has_some_license(self):
+ """Search the file for some license text. If the text is
+ found, return 1"""
+ header = self.get_header()
+ if not re.search("ZPL", header, re.I):
+ return 0
+ else:
+ return 1
+
+
+ def has_license(self):
+ """Fast check for the exact license text in the header"""
+ header = self.get_header()
+ if header.find(self.license) == -1:
+ return 0
+ else:
+ return 1
+
+
+ def include(self):
+ """Put a license text at the top of the lines. If the first line
+ starts with a bang-path start inserting at the second line"""
+ lines = open(self.fname,'r').readlines()
+ start = 0
+ if lines and re.match('#!', lines[0]):
+ start=1
+ lines.insert(start, self.license)
+ # keep the current stat_mod
+ fmode = os.stat(self.fname)[0]
+ # There can already be a backup file from the removal pass
+ if self.backup and not os.path.isfile(self.fname+'.no_license'):
+ os.rename(self.fname, self.fname+'.no_license')
+ open(self.fname, 'w').write(''.join(lines))
+ os.chmod(self.fname, fmode)
+ if self.verbose:
+ print 'License included: %s' % self.fname
+ return
+
+
+ def change(self):
+ """Try to change the license text in the file, raise an exception
+ if not possible.
+ """
+ if self.has_some_license():
+ # try to remove the old license
+ try:
+ self.remove()
+ self.include()
+ except ZLicenseCheckError:
+ open(self.fname+'.pathological','w')
+ raise ZLicenseCheckError('License could not be changed',
+ self.fname)
+
+ else:
+ self.include()
+ return
+
+
+ def remove(self):
+ lines = open(self.fname, 'r').readlines()
+ if not lines:
+ return
+ start = 0
+ save = []
+ if re.match('#!',lines[0]):
+ start = 1
+ save.extend(lines[0])
+ end=start
+ for line in lines[start:]:
+ if line[0] == '#' or line.isspace():
+ end += 1
+ else:
+ break
+
+ license = ''.join(lines[start:end])
+ # test if we really have the license
+ lookfor = 'copyright|Zope Public|license|All rights reserved'
+ if not re.search(lookfor, license, re.I):
+ raise ZLicenseCheckError('No clear license text', self.fname)
+ else:
+ save.extend(lines[end:])
+ # keep the current stat_mod
+ fmode = os.stat(self.fname)[0]
+ if self.backup:
+ os.rename(self.fname, self.fname+'.no_license')
+ if self.verbose:
+ print 'License removed: %s' % self.fname
+ open(self.fname,'w').write(''.join(save))
+ os.chmod(self.fname, fmode)
+ return
+
+
+ def warn(self):
+ print 'File %s has no license text' % self.fname
+
+class Config:
+ """Container to keep configuration options"""
+ def __init__(self, **kws):
+ self.verbose = 0
+ self.warning = 0
+ self.strict = 0
+ self.backup = 1
+ self.undo = 0
+ self.include_init = 0
+ self.license_path='./'
+
+ if kws:
+ for key,value in kws:
+ setattr(self, key, value)
+
+ return
+
+
+class ZPL:
+ def __init__(self, path='./'):
+ self.path = path
+ self.license_text = self.get_text()
+
+ def get_text(self):
+ zhome = os.environ.get('ZOPE_HOME', self.path)
+ try:
+ data = open(os.path.join(zhome,'zpl.py'),'r').read()
+ except IOError:
+ sys.exit('Could not open license file zpl.py')
+
+ license = data[:data.find('"""')]
+ return license
+
+
+class CheckerApp:
+ def __init__(self, config):
+ self.conf = config
+ self.zpl = ZPL()
+ self.pathological = []
+
+ # Which test (uses unbound methods)
+ if self.conf.strict:
+ self.condition = HeaderCheck.has_license
+ else:
+ self.condition = HeaderCheck.has_some_license
+
+ # Wich action
+ if self.conf.warning:
+ self.action = HeaderCheck.warn
+ else:
+ if self.conf.strict:
+ self.action = HeaderCheck.change
+ else:
+ self.action = HeaderCheck.include
+
+ def run(self):
+ if self.conf.undo:
+ for fname in GlobDirectoryWalker(self.conf.path,"*.no_license"):
+ old_name = os.path.splitext(fname)[0]
+ os.rename(fname, old_name)
+ else:
+ for fname in GlobDirectoryWalker(".", "*.py"):
+ if (os.path.split(fname)[-1] == '__init__.py') and \
+ not self.conf.include_init:
+ if self.conf.verbose:
+ print 'Skipping: %s' % fname
+ continue
+
+ hc = HeaderCheck(fname, self.zpl,
+ verbose=self.conf.verbose,
+ backup=self.conf.backup)
+
+ # unbound methods need an instance
+ if not self.condition(hc):
+ try:
+ self.action(hc)
+ except ZLicenseCheckError, error:
+ print error, '(%s)' %error.fname
+ self.pathological.append(fname)
+
+ if self.conf.verbose:
+ for fname in self.pathological:
+ print 'Could not be changed: %s' % fname
+ print 'Number of pathological files: %s' % \
+ len(self.pathological)
+
+
+def print_usage(msg=0):
+ print usage % (sys.argv[0], sys.argv[0])
+ if msg:
+ print msg
+ msg=1
+ sys.exit(msg)
+
+
+def main():
+ import getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "vwcshl:",
+ ["nobackup","undo","include_init"])
+ except getopt.GetoptError, error:
+ print_usage(str(error).capitalize())
+
+ if not opts:
+ print_usage('Need at least optin -w OR -c OR --undo')
+
+ if (('-w','') in opts) and (('-c','') in opts):
+ print_usage('Only option -w OR -c can be used')
+
+ conf=Config()
+ for o,a in opts:
+ if o == '-v' : conf.verbose = 1
+ elif o == '-c': conf.change = 1
+ elif o == '-w': conf.warning = 1
+ elif o == '-s': conf.strict = 1
+ elif o == '-h': print_usage()
+ elif o == '--include_init': conf.include_init = 1
+ elif o == '--nobackup': conf.backup = 0
+ elif o == '--undo': conf.undo = 1
+ elif o == '-l':
+ if not a:
+ print_usage('Need to get a path for option -l')
+ conf.license_path = a
+
+ if not args:
+ conf.path = os.getcwd()
+ else:
+ conf.path = args[0]
+
+ # test presence of working directory
+ if not os.path.isdir(conf.path):
+ print_usage('Can not find directory %s' % conf.path)
+
+ checker = CheckerApp(conf)
+ checker.run()
+
+
+if __name__ == '__main__':
+ main()
=== Zope3/utilities/unittestgui.py 1.1 => 1.2 ===
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+GUI framework and application for use with Python unit testing framework.
+Execute tests written using the framework provided by the 'unittest' module.
+
+Further information is available in the bundled documentation, and from
+
+ http://pyunit.sourceforge.net/
+
+Copyright (c) 1999, 2000, 2001 Steve Purcell
+This module is free software, and you may redistribute it and/or modify
+it under the same terms as Python itself, so long as this copyright message
+and disclaimer are retained in their original form.
+
+IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+"""
+
+__author__ = "Steve Purcell (stephen_purcell@yahoo.com)"
+__version__ = "$Revision$"[11:-2]
+
+import linecache
+import unittest
+import ScrolledText
+import sys
+import Tkinter
+import tkMessageBox
+import traceback
+
+import string
+import re
+tk = Tkinter # Alternative to the messy 'from Tkinter import *' often seen
+
+
+##############################################################################
+# GUI framework classes
+##############################################################################
+
+class BaseGUITestRunner:
+ """Subclass this class to create a GUI TestRunner that uses a specific
+ windowing toolkit. The class takes care of running tests in the correct
+ manner, and making callbacks to the derived class to obtain information
+ or signal that events have occurred.
+ """
+ def __init__(self, *args, **kwargs):
+ self.currentResult = None
+ self.running = 0
+ self.__rollbackImporter = None
+ apply(self.initGUI, args, kwargs)
+
+ def getSelectedTestName(self):
+ "Override to return the name of the test selected to be run"
+ pass
+
+ def errorDialog(self, title, message):
+ "Override to display an error arising from GUI usage"
+ pass
+
+ def runClicked( self
+ , COMMA_SPACE=re.compile( '[, ]+' )
+ ):
+ "To be called in response to user choosing to run a test"
+ if self.running: return
+ testName = self.getSelectedTestName()
+ if not testName:
+ self.errorDialog("Test name entry", "You must enter a test name")
+ return
+ if self.__rollbackImporter:
+ self.__rollbackImporter.rollbackImports()
+ self.__rollbackImporter = RollbackImporter()
+ try:
+ test = unittest.defaultTestLoader.loadTestsFromNames(
+ COMMA_SPACE.split( testName ) )
+ warnings = getattr( test, 'warnings', [] )
+ for sub_test in test._tests:
+ warnings.extend( getattr( sub_test, 'warnings', [] ) )
+ test.warnings = warnings
+ except:
+ exc_type, exc_value, exc_tb = sys.exc_info()
+ apply(traceback.print_exception,sys.exc_info())
+ self.errorDialog("Unable to run test '%s'" % testName,
+ "Error loading specified test: %s, %s" % \
+ (exc_type, exc_value))
+ return
+ self.currentResult = GUITestResult(self)
+ self.totalTests = test.countTestCases()
+ self.running = 1
+ self.notifyRunning()
+ warnings = getattr( test, 'warnings', () )
+ for warning in warnings:
+ self.notifyWarning( warning[0], warning[1] )
+ test.run(self.currentResult)
+ self.running = 0
+ self.notifyStopped()
+
+ def stopClicked(self):
+ "To be called in response to user stopping the running of a test"
+ if self.currentResult:
+ self.currentResult.stop()
+
+ # Required callbacks
+
+ def notifyRunning(self):
+ "Override to set GUI in 'running' mode, enabling 'stop' button etc."
+ pass
+
+ def notifyStopped(self):
+ "Override to set GUI in 'stopped' mode, enabling 'run' button etc."
+ pass
+
+ def notifyWarning(self, msg, tb_str):
+ "Override to log a warning message (e.g., couldn't import a test)."
+
+ def notifyTestFailed(self, test, err):
+ "Override to indicate that a test has just failed"
+ pass
+
+ def notifyTestErrored(self, test, err):
+ "Override to indicate that a test has just errored"
+ pass
+
+ def notifyTestStarted(self, test):
+ "Override to indicate that a test is about to run"
+ pass
+
+ def notifyTestFinished(self, test):
+ """Override to indicate that a test has finished (it may already have
+ failed or errored)"""
+ pass
+
+
+class GUITestResult(unittest.TestResult):
+ """A TestResult that makes callbacks to its associated GUI TestRunner.
+ Used by BaseGUITestRunner. Need not be created directly.
+ """
+ def __init__(self, callback):
+ unittest.TestResult.__init__(self)
+ self.callback = callback
+
+ def addError(self, test, err):
+ unittest.TestResult.addError(self, test, err)
+ self.callback.notifyTestErrored(test, err)
+
+ def addFailure(self, test, err):
+ unittest.TestResult.addFailure(self, test, err)
+ self.callback.notifyTestFailed(test, err)
+
+ def stopTest(self, test):
+ unittest.TestResult.stopTest(self, test)
+ self.callback.notifyTestFinished(test)
+
+ def startTest(self, test):
+ unittest.TestResult.startTest(self, test)
+ self.callback.notifyTestStarted(test)
+
+
+class RollbackImporter:
+ """This tricky little class is used to make sure that modules under test
+ will be reloaded the next time they are imported.
+ """
+ def __init__(self):
+ self.previousModules = sys.modules.copy()
+
+ def rollbackImports(self):
+ for modname in sys.modules.keys():
+ if not self.previousModules.has_key(modname):
+ # Force reload when modname next imported
+ del(sys.modules[modname])
+ linecache.checkcache()
+
+
+##############################################################################
+# Tkinter GUI
+##############################################################################
+
+_ABOUT_TEXT="""\
+PyUnit unit testing framework.
+
+For more information, visit
+http://pyunit.sourceforge.net/
+
+Copyright (c) 2000 Steve Purcell
+<stephen_purcell@yahoo.com>
+"""
+_HELP_TEXT="""\
+Enter the name of a callable object which, when called, will return a \
+TestCase or TestSuite. Click 'start', and the test thus produced will be run.
+
+Double click on an error in the listbox to see more information about it,\
+including the stack trace.
+
+For more information, visit
+http://pyunit.sourceforge.net/
+or see the bundled documentation
+"""
+
+class TkTestRunner(BaseGUITestRunner):
+ """An implementation of BaseGUITestRunner using Tkinter.
+ """
+ def initGUI(self, root, initialTestName):
+ """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
+ # Set up values that will be tied to widgets
+ self.suiteNameVar = tk.StringVar()
+ self.suiteNameVar.set(initialTestName)
+ self.statusVar = tk.StringVar()
+ self.statusVar.set("Idle")
+ self.runCountVar = tk.IntVar()
+ self.failCountVar = tk.IntVar()
+ self.errorCountVar = tk.IntVar()
+ self.remainingCountVar = tk.IntVar()
+ self.top = tk.Frame()
+ self.top.pack(fill=tk.BOTH, expand=1)
+ self.createWidgets()
+
+ def createWidgets(self):
+ """Creates and packs the various widgets.
+
+ Why is it that GUI code always ends up looking a mess, despite all the
+ best intentions to keep it tidy? Answers on a postcard, please.
+ """
+ # Status bar
+ statusFrame = tk.Frame(self.top, relief=tk.SUNKEN, borderwidth=2)
+ 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)
+ 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)
+ e.focus_set()
+ e.bind('<Key-Return>', lambda e, self=self: self.runClicked())
+
+ # 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)
+ self.progressBar = ProgressBar(progressFrame, relief=tk.SUNKEN,
+ borderwidth=2)
+ self.progressBar.pack(fill=tk.X, expand=1)
+
+ # 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)
+ self.stopGoButton = tk.Button(buttonFrame, text="Start",
+ command=self.runClicked)
+ self.stopGoButton.pack(fill=tk.X)
+ tk.Button(buttonFrame, text="Close",
+ command=self.top.quit).pack(side=tk.BOTTOM, fill=tk.X)
+ tk.Button(buttonFrame, text="About",
+ command=self.showAboutDialog).pack(side=tk.BOTTOM, fill=tk.X)
+ tk.Button(buttonFrame, text="Help",
+ 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)
+
+ # List box showing errors and failures
+ 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)
+ self.errorListbox = tk.Listbox(listFrame, foreground='red',
+ selectmode=tk.SINGLE,
+ selectborderwidth=0)
+ self.errorListbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=1,
+ anchor=tk.NW)
+ listScroll = tk.Scrollbar(listFrame, command=self.errorListbox.yview)
+ listScroll.pack(side=tk.LEFT, fill=tk.Y, anchor=tk.N)
+ self.errorListbox.bind("<Double-1>",
+ lambda e, self=self: self.showSelectedError())
+ self.errorListbox.configure(yscrollcommand=listScroll.set)
+
+ # List box showing warnings
+ 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)
+ self.warningListbox = tk.Listbox(warnFrame, foreground='black',
+ selectmode=tk.SINGLE,
+ selectborderwidth=0)
+ self.warningListbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=1,
+ anchor=tk.NW)
+ wListScroll = tk.Scrollbar(warnFrame, command=self.warningListbox.yview)
+ wListScroll.pack(side=tk.LEFT, fill=tk.Y, anchor=tk.N)
+ self.warningListbox.bind("<Double-1>",
+ lambda e, self=self: self.showSelectedWarning())
+ self.warningListbox.configure(yscrollcommand=wListScroll.set)
+
+
+ def getSelectedTestName(self):
+ return self.suiteNameVar.get()
+
+ def errorDialog(self, title, message):
+ tkMessageBox.showerror(parent=self.root, title=title,
+ message=message)
+
+ def notifyRunning(self):
+ self.runCountVar.set(0)
+ self.failCountVar.set(0)
+ self.errorCountVar.set(0)
+ self.remainingCountVar.set(self.totalTests)
+ self.errorInfo = []
+ self.warnInfo = []
+ while self.errorListbox.size():
+ self.errorListbox.delete(0)
+ while self.warningListbox.size():
+ self.warningListbox.delete(0)
+ #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)
+ self.top.update_idletasks()
+
+ def notifyStopped(self):
+ self.stopGoButton.config(state=tk.ACTIVE)
+ #self.stopGoButton.config(command=self.runClicked, text="Start")
+ self.statusVar.set("Idle")
+
+ def notifyTestStarted(self, test):
+ self.statusVar.set(str(test))
+ self.top.update_idletasks()
+
+ def notifyWarning(self, msg, tb_str):
+ self.warningListbox.insert(tk.END, "Warning: %s" % msg)
+ self.warnInfo.append((msg,tb_str))
+
+ def notifyTestFailed(self, test, err):
+ self.failCountVar.set(1 + self.failCountVar.get())
+ self.errorListbox.insert(tk.END, "Failure: %s" % test)
+ self.errorInfo.append((test,err))
+
+ def notifyTestErrored(self, test, err):
+ self.errorCountVar.set(1 + self.errorCountVar.get())
+ self.errorListbox.insert(tk.END, "Error: %s" % test)
+ self.errorInfo.append((test,err))
+
+ 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)
+ fillColor = len(self.errorInfo) and "red" or "green"
+ self.progressBar.setProgressFraction(fractionDone, fillColor)
+
+ def showAboutDialog(self):
+ tkMessageBox.showinfo(parent=self.root, title="About PyUnit",
+ message=_ABOUT_TEXT)
+
+ def showHelpDialog(self):
+ tkMessageBox.showinfo(parent=self.root, title="PyUnit help",
+ message=_HELP_TEXT)
+
+ def showSelectedError(self):
+ selection = self.errorListbox.curselection()
+ if not selection: return
+ selected = int(selection[0])
+ txt = self.errorListbox.get(selected)
+ window = tk.Toplevel(self.root)
+ window.title(txt)
+ window.protocol('WM_DELETE_WINDOW', window.quit)
+ test, error = self.errorInfo[selected]
+ tk.Label(window, text=str(test),
+ foreground="red", justify=tk.LEFT).pack(anchor=tk.W)
+ tracebackLines = apply(traceback.format_exception, error + (10,))
+ tracebackText = string.join(tracebackLines,'')
+ text = ScrolledText.ScrolledText(window)
+ text.tag_config('sel', relief=tk.FLAT)
+ text.insert(tk.END, tracebackText)
+ if len(tracebackLines) < 20:
+ text.config(height=len(tracebackLines) + 5)
+ text.yview_pickplace(tk.END)
+ text['state'] = tk.DISABLED
+ text.pack(expand=1, fill=tk.BOTH)
+ b = tk.Button(window, text="Close",
+ command=window.quit)
+ b.pack(side=tk.BOTTOM)
+ b.focus_set()
+ window.bind('<Key-Return>', lambda e, w=window: w.quit())
+ window.mainloop()
+ window.destroy()
+
+ def showSelectedWarning(self):
+ selection = self.warningListbox.curselection()
+ if not selection: return
+ selected = int(selection[0])
+ txt = self.warningListbox.get(selected)
+ window = tk.Toplevel(self.root)
+ window.title(txt)
+ window.protocol('WM_DELETE_WINDOW', window.quit)
+ test, error = self.warnInfo[selected]
+ tk.Label(window, text=str(test),
+ foreground="black", justify=tk.LEFT).pack(anchor=tk.W)
+ tk.Label(window, text=error, justify=tk.LEFT).pack()
+ tk.Button(window, text="Close",
+ command=window.quit).pack(side=tk.BOTTOM)
+ window.bind('<Key-Return>', lambda e, w=window: w.quit())
+ window.mainloop()
+ window.destroy()
+
+
+class ProgressBar(tk.Frame):
+ """A simple progress bar that shows a percentage progress in
+ the given colour."""
+
+ def __init__(self, *args, **kwargs):
+ apply(tk.Frame.__init__, (self,) + args, kwargs)
+ self.canvas = tk.Canvas(self, height='20', width='60',
+ background='white', borderwidth=3)
+ self.canvas.pack(fill=tk.X, expand=1)
+ self.rect = self.text = None
+ self.canvas.bind('<Configure>', self.paint)
+ self.setProgressFraction(0.0)
+
+ def setProgressFraction(self, fraction, color='blue'):
+ self.fraction = fraction
+ self.color = color
+ self.paint()
+ self.canvas.update_idletasks()
+
+ def paint(self, *args):
+ totalWidth = self.canvas.winfo_width()
+ width = int(self.fraction * float(totalWidth))
+ height = self.canvas.winfo_height()
+ if self.rect is not None: self.canvas.delete(self.rect)
+ 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)
+ self.text = self.canvas.create_text(totalWidth/2, height/2,
+ anchor=tk.CENTER,
+ text=percentString)
+
+def main(initialTestName=""):
+ root = tk.Tk()
+ root.title("PyUnit")
+ runner = TkTestRunner(root, initialTestName)
+ root.protocol('WM_DELETE_WINDOW', root.quit)
+ root.mainloop()
+
+
+if __name__ == '__main__':
+ import sys
+ if len(sys.argv) == 2:
+ main(sys.argv[1])
+ else:
+ main()
=== Zope3/utilities/ExtensionBuilder.py 1.4 => 1.5 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
"""Build Python extension modules from Setup files. Particularly
designed for building extensions for Zope in a way that works
the same way for *nix and win32. Note that for building Zope
@@ -437,7 +450,7 @@
win32_def="""EXPORTS
- init%(module)s
+ init%(module)s
"""
win32_mak="""# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
@@ -497,11 +510,11 @@
ALL : "$(OUTDIR)\\%(module)s.dll"
CLEAN :
- -@erase "$(OUTDIR)\\%(module)s.dll"
- -@erase "$(OUTDIR)\\%(module)s.obj"%(other_clean_release)s
- -@erase "$(OUTDIR)\\%(module)s.lib"
- -@erase "$(OUTDIR)\\%(module)s.exp"
- -@erase "$(OUTDIR)\\%(module)s.pch"
+ -@erase "$(OUTDIR)\\%(module)s.dll"
+ -@erase "$(OUTDIR)\\%(module)s.obj"%(other_clean_release)s
+ -@erase "$(OUTDIR)\\%(module)s.lib"
+ -@erase "$(OUTDIR)\\%(module)s.exp"
+ -@erase "$(OUTDIR)\\%(module)s.pch"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
@@ -531,10 +544,10 @@
/pdb:"$(OUTDIR)\\%(module)s.pdb" /machine:I386 /def:".\\%(module)s.def"\\
/out:"$(OUTDIR)\\%(module)s.dll" /implib:"$(OUTDIR)\\%(module)s.lib" %(libdirs)s
DEF_FILE= \\
- ".\\%(module)s.def"
+ ".\\%(module)s.def"
LINK32_OBJS= \\
- "$(INTDIR)\\%(module)s.obj" \\%(other_link)s
- "%(pyhome)s\\libs\\%(pythonlib)s"
+ "$(INTDIR)\\%(module)s.obj" \\%(other_link)s
+ "%(pyhome)s\\libs\\%(pythonlib)s"
"$(OUTDIR)\\%(module)s.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
@@ -559,15 +572,15 @@
ALL : "$(OUTDIR)\\%(module)s.dll"
CLEAN :
- -@erase "$(OUTDIR)\\%(module)s.dll"
- -@erase "$(OUTDIR)\\%(module)s.obj"%(other_clean_debug)s
- -@erase "$(OUTDIR)\\%(module)s.ilk"
- -@erase "$(OUTDIR)\\%(module)s.lib"
- -@erase "$(OUTDIR)\\%(module)s.exp"
- -@erase "$(OUTDIR)\\%(module)s.pdb"
- -@erase "$(OUTDIR)\\%(module)s.pch"
- -@erase "$(OUTDIR)\\pcbuild.pdb"
- -@erase "$(OUTDIR)\\pcbuild.idb"
+ -@erase "$(OUTDIR)\\%(module)s.dll"
+ -@erase "$(OUTDIR)\\%(module)s.obj"%(other_clean_debug)s
+ -@erase "$(OUTDIR)\\%(module)s.ilk"
+ -@erase "$(OUTDIR)\\%(module)s.lib"
+ -@erase "$(OUTDIR)\\%(module)s.exp"
+ -@erase "$(OUTDIR)\\%(module)s.pdb"
+ -@erase "$(OUTDIR)\\%(module)s.pch"
+ -@erase "$(OUTDIR)\\pcbuild.pdb"
+ -@erase "$(OUTDIR)\\pcbuild.idb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
@@ -598,10 +611,10 @@
/pdb:"$(OUTDIR)\\%(module)s.pdb" /debug /machine:I386 /def:".\\%(module)s.def"\\
/out:"$(OUTDIR)\\%(module)s.dll" /implib:"$(OUTDIR)\\%(module)s.lib" %(libdirs)s
DEF_FILE= \\
- ".\\%(module)s.def"
+ ".\\%(module)s.def"
LINK32_OBJS= \\
- "$(INTDIR)\\%(module)s.obj" \\%(other_link)s
- "%(pyhome)s\\libs\\%(pythonlib)s"
+ "$(INTDIR)\\%(module)s.obj" \\%(other_link)s
+ "%(pyhome)s\\libs\\%(pythonlib)s"
"$(OUTDIR)\\%(module)s.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
=== Zope3/utilities/FS.py 1.8 => 1.9 ===
#
-# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
+# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-
import struct, tempfile, string, time, pickle, os, sys
from struct import pack, unpack
from cStringIO import StringIO
=== Zope3/utilities/bbb.py 1.14 => 1.15 ===
#
-# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
+# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Read and (re-)format BoboPOS 2 database files
=== Zope3/utilities/check_catalog.py 1.4 => 1.5 ===
-
##############################################################################
#
-# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
+# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-
""" script to consistency of a ZCatalog """
__version__='$Revision$'[11:-2]
=== Zope3/utilities/fixbbbts.py 1.2 => 1.3 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
import sys
__doc__="""Fix BoboPOS time stamps
=== Zope3/utilities/load_site.py 1.9 => 1.10 ===
#
-# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
+# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Load a Zope site from a collection of files or directories
=== Zope3/utilities/requestprofiler.py 1.16 => 1.17 === (479/579 lines abridged)
-
+#!/usr/bin/env python2.1
##############################################################################
#
-# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
+# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-
""" Request log profiler script """
__version__='$Revision$'[11:-2]
-import string, sys, time, getopt, tempfile, math, cPickle
-try: import gzip
-except: pass
+import string, sys, time, getopt, tempfile
class ProfileException(Exception): pass
@@ -62,13 +59,6 @@
return time.strftime('%Y-%m-%dT%H:%M:%S', t)
else:
return "NA"
-
- def shortprettystart(self):
- if self.start is not None:
- t = time.localtime(self.start)
- return time.strftime('%H:%M:%S', t)
- else:
- return "NA"
def win(self):
if self.t_recdinput is not None and self.start is not None:
@@ -263,68 +253,45 @@
file.seek(file.tell() - linelen)
return retn
-
-def get_requests(files, start=None, end=None, statsfname=None,
- writestats=None, readstats=None):
[-=- -=- -=- 479 lines omitted -=- -=- -=-]
- now = time.localtime(time.time() - int(val)*3600*24 )
+ now = time.gmtime(time.time())
# for testing - now = (2001, 04, 19, 0, 0, 0, 0, 0, -1)
start = list(now)
start[3] = start[4] = start[5] = 0
@@ -782,11 +615,7 @@
mode='cumulative'
if opt=='--timed':
mode='timed'
- if opt=='--urlfocus':
- mode='urlfocus'
- urlfocusurl = val
- if opt=='--urlfocustime':
- urlfocustime=int(val)
+
validcumsorts = ['url', 'hits', 'hangs', 'max', 'min', 'median',
'mean', 'total']
@@ -810,16 +639,13 @@
sortf = codesort
else:
sortf = Sort(sortby)
+
elif mode=='timed':
- sortf = None
- elif mode=='urlfocus':
- sortf = Sort('start', ascending=1)
+ sortf = timesort
else:
raise 'Invalid mode'
-
- req=get_requests(files, start, end, statsfname, writestats, readstats)
- analyze(req, top, sortf, start, end, mode, resolution, urlfocusurl,
- urlfocustime)
+
+ analyze(files, top, sortf, start, end, mode, resolution)
except AssertionError, val:
a = "%s is not a valid %s sort spec, use one of %s"
@@ -838,3 +664,10 @@
traceback.print_exc()
print usage()
sys.exit(0)
+
+
+
+
+
+
+
=== Zope3/utilities/testrunner.py 1.25 => 1.26 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
"""testrunner - a Zope test suite utility.
The testrunner utility is used to execute PyUnit test suites. You can find
@@ -53,20 +66,10 @@
name, ext=os.path.splitext(filename)
file, pathname, desc=imp.find_module(name, [path])
saved_syspath = sys.path[:]
- module = None
try:
- sys.path.append(path) # let module find things in its dir
- try:
- module=imp.load_module(name, file, pathname, desc)
- except:
- (tb_t, tb_v, tb_tb) = sys.exc_info()
- self.report("Module %s failed to load\n%s: %s" % (pathname,
- tb_t, tb_v))
- self.report(string.join(traceback.format_tb(tb_tb)) + '\n')
- del tb_tb
+ module=imp.load_module(name, file, pathname, desc)
finally:
file.close()
- sys.path.pop() # Remove module level path
sys.path[:] = saved_syspath
function=getattr(module, 'test_suite', None)
if function is None:
@@ -90,7 +93,7 @@
return 0
def runSuite(self, suite):
- runner=unittest.TextTestRunner(stream=sys.stderr, verbosity=self.verbosity)
+ runner=unittest.TextTestRunner(verbosity=self.verbosity)
self.results.append(runner.run(suite))
def report(self, message):
@@ -192,15 +195,6 @@
sys.stderr.write( '*** Restoring directory to: %s\n' % working_dir )
os.chdir(working_dir)
-def remove_stale_bytecode(arg, dirname, names):
- names = map(os.path.normcase, names)
- for name in names:
- if name.endswith(".pyc") or name.endswith(".pyo"):
- srcname = name[:-1]
- if srcname not in names:
- fullname = os.path.join(dirname, name)
- print "Removing stale bytecode file", fullname
- os.unlink(fullname)
def main(args):
@@ -266,11 +260,6 @@
whether it succeeded. Running with -q is the same as
running with -v1.
- -o filename
-
- Output test results to the specified file rather than
- to stderr.
-
-h
Display usage information.
@@ -283,7 +272,7 @@
mega_suite = 1
set_python_path = 1
- options, arg=getopt.getopt(args, 'amPhd:f:v:qMo:')
+ options, arg=getopt.getopt(args, 'amPhd:f:v:qM')
if not options:
err_exit(usage_msg)
for name, value in options:
@@ -308,14 +297,9 @@
verbosity = int(value)
elif name == 'q':
verbosity = 1
- elif name == 'o':
- f = open(value,'w')
- sys.stderr = f
else:
err_exit(usage_msg)
- os.path.walk(os.curdir, remove_stale_bytecode, None)
-
testrunner = TestRunner( os.getcwd()
, verbosity=verbosity
, mega_suite=mega_suite)
@@ -329,13 +313,6 @@
testrunner.report( "Adding %s to sys.path." % sw_home )
sys.path.insert( 0, sw_home )
os.environ['SOFTWARE_HOME'] = sw_home
-
- try:
- # Try to set up the testing environment (esp. INSTANCE_HOME,
- # so we use the right custom_zodb.py.)
- import Testing
- except ImportError:
- pass
if test_all:
testrunner.runAllTests()