[Zope-Checkins] CVS: Zope3/lib/python/Zope/Testing - Builder.py:1.2 CleanUp.py:1.2 ZODButil.py:1.3 __init__.py:1.6 common.py:1.4 custom_zodb.py:1.3 dispatcher.py:1.5 makerequest.py:1.5

Jim Fulton jim@zope.com
Mon, 10 Jun 2002 19:30:16 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Testing
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/Testing

Modified Files:
	ZODButil.py __init__.py common.py custom_zodb.py dispatcher.py 
	makerequest.py 
Added Files:
	Builder.py CleanUp.py 
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.

=== Zope3/lib/python/Zope/Testing/Builder.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.
+# 
+##############################################################################
+"""
+    Utilities for buliding test suites by crawling directories.
+"""
+
+import unittest
+import sys, os
+from fnmatch import fnmatch
+import traceback
+
+global_exceptions = {'Zope.Server.medusa.sendfile.test_sendfile':1,}
+
+def listTestableNames( pathname ):
+    """
+        Return a list of the names to be traversed to build tests.
+    """
+    names = os.listdir( pathname )
+
+    if '.testinfo' in names:  # allow local control
+
+        f     = open( os.path.join( pathname, '.testinfo' ) )
+        lines = filter( None, f.readlines() )
+        f.close()
+
+        lines = map( lambda x:                  # remove trailing newlines
+                         x[-1]=='\n' and x[:-1] or x
+                   , lines )
+
+        names = filter( lambda x:               # skip comments
+                         x and x[0] != '#'
+                      , lines )
+
+    return names
+
+class TestFinder( unittest.TestLoader ):
+    """
+        Crawl the filesystem, looking for tests.
+    """
+    def __init__( self, root_dir=None ):
+
+        if root_dir is None:
+            root_dir = self._guessSoftwareHome()
+
+        self._root_dir      = root_dir
+        self._root_dir_len  = len( root_dir.split( os.sep ) )
+        self._candidates    = []
+        self._cant_load     = []
+        self._maybe_cant_load = {}
+
+    def _guessSoftwareHome( self ):
+        """
+            Attempt to guess where SOFTWARE_HOME is.
+        """
+        from Zope import Testing
+        zope_pkg, rest = os.path.split( Testing.__path__[0] )
+        root_dir, rest = os.path.split( zope_pkg )
+        return root_dir
+
+    def _splitPath( self, path ):
+        """
+            Return a list of path elements, relative to root_dir.
+        """
+        return path.split( os.sep )[ self._root_dir_len : ]
+
+    def _visit( self, arg, dirname, names ):
+        """
+            Visitor for os.path.walk.
+        """
+        names[:] = listTestableNames( dirname )
+        for name in names:
+            if fnmatch( name, 'test*.py' ) and name != 'testrunner.py':
+                self._addCandidate( dirname, name )
+
+    def _addCandidate( self, dirname, name ):
+        """
+            Append a candidate module path.
+        """
+        elements = self._splitPath( dirname )
+        basename, ext = os.path.splitext( name )
+        elements.append( basename )
+        self._candidates.append( '.'.join( elements ) )
+
+    def _formatException( self, candidate, msg ):
+        """
+            Grab the traceback and store, along with header info.
+        """
+        header = '[%s] %s' % ( candidate, msg )
+        errLines = apply( traceback.format_exception, sys.exc_info() )
+        body = ''.join(errLines)
+        return header, body
+
+    def _recordLoadFailure( self, candidate, msg ):
+        header, body = self._formatException(candidate, msg)
+        self._cant_load.append( ( header, body ) )
+
+    def _deferLoadFailure( self, candidate, msg ):
+        header, body = self._formatException(candidate, msg)
+        self._maybe_cant_load[candidate] = (header, body)
+
+    def _do_import( self, module ):
+        mod = __import__(module)
+        for name in module.split('.')[1:]:
+            mod = getattr(mod, name)
+        return mod
+
+    def _buildSuite( self ):
+        """
+            Build a suite from our candidate modules.
+        """
+        suite = unittest.TestSuite()
+        self._cant_load = []
+        self._loaded = []
+
+        for candidate in self._candidates:
+            if candidate in global_exceptions:
+                continue
+
+            try:
+                mod = self._do_import(candidate)
+            except ImportError:
+                tb = ''.join(traceback.format_exception(*sys.exc_info()))
+                self._cant_load.append(("Failed to import " + candidate, tb))
+                continue
+
+            if hasattr(mod, "test_suite"):
+                suite.addTest(mod.test_suite())
+                continue
+
+            try:
+                suite.addTest(self.loadTestsFromModule(mod))
+            except Exception, msg:
+                if self._maybe_cant_load.get(candidate):
+                    self._cant_load.append(self._maybe_cant_load[candidate])
+                self._recordLoadFailure('%s (implicit)' % candidate, msg)
+            else:
+                self._loaded.append( '%s (implicit)' % candidate )
+        return suite
+
+    def _loadTestsFromPath( self, path=None ):
+        if path is None:
+            path = self._root_dir
+        os.path.walk( path, self._visit, None )
+        suite = self._buildSuite()
+        suite.warnings = self._cant_load
+        suite.loaded = self._loaded
+        if suite.warnings:
+            print "There were failures loading tests"
+            print
+            for item in suite.warnings:
+                print item
+                print
+        return suite
+
+    __call__ = _loadTestsFromPath
+
+def allZopeTests():
+    import Zope
+    return TestFinder()( Zope.__path__[0] )


=== Zope3/lib/python/Zope/Testing/CleanUp.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.
+# 
+##############################################################################
+"""Provide a standard cleanup registry
+
+Unit tests that change global data should include the CleanUp base
+class, which provides simpler setUp and tearDown methods that call
+global-data cleanup routines::
+
+  class Test(CleanUp, unittest.TestCase):
+
+      ....
+
+If custom setUp or tearDown are needed, then the base reoutines should
+be called, as in::
+
+  def tearDown(self):
+      CleanUp.tearDown(self)
+      ....
+
+Cleanup routines for global data should be registered by passing them to
+addCleanup::
+
+  from Zope.Testing.CleanUp import addCleanUp
+  addCleanUp(roleRegistry._clear)
+
+
+Revision information:
+$Id$
+"""
+
+_cleanups = []
+
+def addCleanUp(func, args=(), kw={}):
+    """Register a cleanup routines
+
+    Pass a function to be called to cleanup global data.
+    Optional argument tuple and keyword arguments may be passed.
+    """
+    _cleanups.append((func, args, kw))
+
+def cleanUp(ignored=None):
+    """Clean up global data
+    """
+    for func, args, kw in _cleanups:
+        func(*args, **kw)
+
+class CleanUp:
+    """Mix-in class providing clean-up setUp and tearDown routines
+    """
+    tearDown = setUp = cleanUp


=== Zope3/lib/python/Zope/Testing/ZODButil.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 os
 from glob import glob
 import ZODB


=== Zope3/lib/python/Zope/Testing/__init__.py 1.5 => 1.6 ===
 #
-# 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.
 # 
 ##############################################################################
 """
@@ -17,17 +18,19 @@
 """
 import os
 
-def pdir(path):
-    return os.path.split(path)[0]
-
-# Set the INSTANCE_HOME to the Testing package directory
-os.environ['INSTANCE_HOME'] = INSTANCE_HOME = pdir(__file__)
-
-# Set the SOFTWARE_HOME to the directory containing the Testing package
-os.environ['SOFTWARE_HOME'] = SOFTWARE_HOME = pdir(INSTANCE_HOME)
-
-# Note: we don't set os.environ['ZEO_CLIENT'] anymore because we
-# really do need all the products to be initialized.  Some tests
-# use the product registry.
-
+def allZopeTests():
+    from Builder import allZopeTests
+    return allZopeTests()
+
+def patchTracebackModule():
+    """Use the ExceptionFormatter to show more info in tracebacks.
+    """
+    from Zope.Exceptions.ExceptionFormatter import format_exception
+    import traceback
+    traceback.format_exception = format_exception
+
+# Don't use the new exception formatter by default, since it
+# doesn't show filenames.
+if os.environ.get('NEW_ZOPE_EXCEPTION_FORMATTER', 0):
+    patchTracebackModule()
 


=== Zope3/lib/python/Zope/Testing/common.py 1.3 => 1.4 ===
+#
+# 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.
+# 
+##############################################################################
+from Types import ClassType
+
 # Default test runner
 TestRunner = unittest.TextTestRunner
 
@@ -20,7 +35,6 @@
 def test_suite():
     # The default test suite includes every subclass of TestCase in
     # the module, with 'test' as the test method prefix.
-    ClassType = type(unittest.TestCase)
     tests = []
     for v in globals().values():
         if isinstance(v, ClassType) and issubclass(v, unittest.TestCase):


=== Zope3/lib/python/Zope/Testing/custom_zodb.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 ZODB, os
 from ZODB.FileStorage import FileStorage
 from ZODB.DemoStorage import DemoStorage


=== Zope3/lib/python/Zope/Testing/dispatcher.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.
 # 
 ##############################################################################
+""" Dispatcher for usage inside Zope test environment
 
-# Dispatcher for usage inside Zope test environment
-# Andreas Jung, andreas@digicool.com 03/24/2001
+Andreas Jung, andreas@digicool.com 03/24/2001
 
-
-__version__ = '$Id$'
+$Id$
+"""
 
 
 import os,sys,re,string
@@ -33,7 +34,7 @@
         self.f_startup = []
         self.f_teardown = []
         self.lastlog = ""
-        self.lock 	    = threading.Lock()
+        self.lock = threading.Lock()
         self.func = func
         self.profiling = 0
 
@@ -74,10 +75,10 @@
         mem_watcher.start()
         
         self.start_test = time.time()
-        self.name 		= name
-        self.th_data    = {}
-        self.runtime    = {}
-        self._threads   = []
+        self.name= name
+        self.th_data = {}
+        self.runtime = {}
+        self._threads= []
         s2s=self.s2s
         
         
@@ -86,11 +87,14 @@
             
             for i in range(0,numthreads):
                 kw['t_func'] = func
-                th = threading.Thread(None,self.worker,name="TH_%s_%03d" % (func,i) ,args=args,kwargs=kw)
+                th = threading.Thread(None,self.worker,
+                        name="TH_%s_%03d" % (func,i) ,args=args,kwargs=kw)
                 self._threads.append(th)
                 
-        for th in self._threads: 			th.start()
-        while threading.activeCount() > 1: time.sleep(1)
+        for th in self._threads:
+            th.start()
+        while threading.activeCount() > 1:
+            time.sleep(1)
         
         self.logn('ID: %s ' % self.name)
         self.logn('FUNC: %s ' % self.func)
@@ -98,16 +102,22 @@
         self.logn('Args: %s' % params)
         
         for th in self._threads:
-            self.logn( '%-30s ........................ %9.3f sec' % (th.getName(), self.runtime[th.getName()]) )
+            self.logn( '%-30s ........................ %9.3f sec'
+                        % (th.getName(), self.runtime[th.getName()]) )
             for k,v in self.th_data[th.getName()].items():
                 self.logn ('%-30s  %-15s = %s' % (' ',k,v) )
                 
                
         self.logn("") 
-        self.logn('Complete running time:                                  %9.3f sec' % (time.time()-self.start_test) )
+        self.logn(
+            'Complete running time:                                  %9.3f sec'
+                % (time.time()-self.start_test) )
         if len(self.mem_usage)>1: self.mem_usage.remove(-1)
-        self.logn( "Memory: start: %s, end: %s, low: %s, high: %s" %  \
-                        (s2s(self.mem_usage[0]),s2s(self.mem_usage[-1]),s2s(min(self.mem_usage)), s2s(max(self.mem_usage))))
+        self.logn( "Memory: start: %s, end: %s, low: %s, high: %s" % 
+                        (s2s(self.mem_usage[0]),
+                         s2s(self.mem_usage[-1]),
+                         s2s(min(self.mem_usage)),
+                         s2s(max(self.mem_usage))))
         self.logn('')
         
         
@@ -119,7 +129,7 @@
         del kw['t_func']
         
         ts = time.time()
-        apply(t_func,args,kw)			
+        apply(t_func,args,kw)                        
         te = time.time()
         
         for func in self.f_teardown: getattr(self,func)()
@@ -129,8 +139,7 @@
     def th_setup(self):
         """ initalize thread with some environment data """
         
-        env = {'start': time.time()
-                  }
+        env = {'start': time.time()}
         return env
         
         
@@ -138,15 +147,17 @@
         """ famous last actions of thread """
         
         self.lock.acquire()
-        self.th_data[ threading.currentThread().getName() ]   = kw
-        self.runtime  [ threading.currentThread().getName() ] = time.time() - env['start']
+        self.th_data[ threading.currentThread().getName() ] = kw
+        self.runtime[ threading.currentThread().getName() ] = ( time.time()
+                                                              - env['start'] )
         self.lock.release()
         
         
     def getmem(self):
         """ try to determine the current memory usage """
        
-        if not sys.platform in ['linux2']: return None
+        if not sys.platform in ['linux2']:
+            return None
         cmd = '/bin/ps --no-headers -o pid,vsize --pid %s' % os.getpid()
         outp = commands.getoutput(cmd)
         pid,vsize = filter(lambda x: x!="" , string.split(outp," ") )
@@ -167,7 +178,8 @@
         while running ==1:
             self.mem_usage.append( self.getmem() )
             time.sleep(1)
-            if threading.activeCount() == 2: running = 0
+            if threading.activeCount() == 2:
+                running = 0
             
             
     def register_startup(self,func):


=== Zope3/lib/python/Zope/Testing/makerequest.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.
 # 
 ##############################################################################
 """