[Scipy-svn] r3853 - in trunk/scipy: linsolve/umfpack/tests misc/tests stats/models testing

scipy-svn@scip... scipy-svn@scip...
Mon Jan 21 14:41:22 CST 2008


Author: matthew.brett@gmail.com
Date: 2008-01-21 14:40:25 -0600 (Mon, 21 Jan 2008)
New Revision: 3853

Modified:
   trunk/scipy/linsolve/umfpack/tests/test_umfpack.py
   trunk/scipy/misc/tests/test_pilutil.py
   trunk/scipy/stats/models/setup.py
   trunk/scipy/testing/decorators.py
   trunk/scipy/testing/utils.py
Log:
Fancy decorator work to do conditional SkipTest exceptions for optional dependencies

Modified: trunk/scipy/linsolve/umfpack/tests/test_umfpack.py
===================================================================
--- trunk/scipy/linsolve/umfpack/tests/test_umfpack.py	2008-01-19 19:43:04 UTC (rev 3852)
+++ trunk/scipy/linsolve/umfpack/tests/test_umfpack.py	2008-01-21 20:40:25 UTC (rev 3853)
@@ -14,10 +14,17 @@
 from scipy.sparse import csc_matrix, dok_matrix, spdiags
 
 import numpy as nm
-import scipy.linsolve.umfpack as um
-
+try:
+    import scipy.linsolve.umfpack as um
+except (ImportError, AttributeError):
+    _have_umfpack = False
+else:
+    _have_umfpack = um.umfpack._um is not None
+    
 # Allow disabling of nose tests if umfpack not present
-TestCase.__test__ = um.umfpack._um is not None
+# See end of file for application
+_umfpack_skip = dec.skipif(not _have_umfpack,
+                           'UMFPACK appears not to be compiled')
 
 class TestSolvers(TestCase):
     """Tests inverting a sparse linear system"""
@@ -165,6 +172,9 @@
         self.complex_matrices = [x.astype(nm.complex128)
                                  for x in self.real_matrices]
 
+# Skip methods if umfpack not present
+for cls in [TestSolvers, TestFactorization]:
+    decorate_methods(cls, _umfpack_skip)
 
 if __name__ == "__main__":
     nose.run(argv=['', __file__])

Modified: trunk/scipy/misc/tests/test_pilutil.py
===================================================================
--- trunk/scipy/misc/tests/test_pilutil.py	2008-01-19 19:43:04 UTC (rev 3852)
+++ trunk/scipy/misc/tests/test_pilutil.py	2008-01-21 20:40:25 UTC (rev 3853)
@@ -11,8 +11,10 @@
 else:
     _have_PIL = True
     import scipy.misc.pilutil as pilutil
-TestCase.__test__ = _have_PIL
 
+# Function / method decorator for skipping PIL tests on import failure
+_pilskip = dec.skipif(not _have_PIL, 'Need to import PIL for this test')
+
 datapath = os.path.dirname(__file__)
 
 class TestPILUtil(TestCase):
@@ -28,14 +30,13 @@
         assert_equal(pilutil.bytescale(x),x)
         assert_equal(pilutil.bytescale(y),[0,127,255])
 
-
 def tst_fromimage(filename, irange):
     img = pilutil.fromimage(PIL.Image.open(filename))
     imin,imax = irange
     assert img.min() >= imin
     assert img.max() <= imax
 
-@dec.setastest(_have_PIL)
+@_pilskip
 def test_fromimage():
     ''' Test generator for parametric tests '''
     data = {'icon.png':(0,255),
@@ -44,5 +45,7 @@
     for fn, irange in data.iteritems():
         yield tst_fromimage, os.path.join(datapath,'data',fn), irange
 
+decorate_methods(TestPILUtil, _pilskip)
+
 if __name__ == "__main__":
     nose.run(argv=['', __file__])

Modified: trunk/scipy/stats/models/setup.py
===================================================================
--- trunk/scipy/stats/models/setup.py	2008-01-19 19:43:04 UTC (rev 3852)
+++ trunk/scipy/stats/models/setup.py	2008-01-21 20:40:25 UTC (rev 3853)
@@ -8,7 +8,6 @@
     config.add_data_dir('tests')
 
     try:
-        import sys
         from scipy.stats.models.bspline_module import mod
         n, s, d = weave_ext(mod)
         config.add_extension(n, s, **d)

Modified: trunk/scipy/testing/decorators.py
===================================================================
--- trunk/scipy/testing/decorators.py	2008-01-19 19:43:04 UTC (rev 3852)
+++ trunk/scipy/testing/decorators.py	2008-01-21 20:40:25 UTC (rev 3853)
@@ -1,5 +1,10 @@
 """Decorators for labeling test objects."""
 
+try:
+    import nose
+except ImportError:
+    pass
+
 def slow(t):
     """Labels a test as 'slow'.
 
@@ -25,9 +30,33 @@
     >>> @setastest(False)
     >>> def func_with_test_in_name(arg1, arg2): pass
     ...
-    >>> 
+    >>>
+    
+    Note that this decorator cannot use the nose namespace, because it
+    can be called from a non-test.
     '''
     def set_test(t):
         t.__test__ = tf
         return t
     return set_test
+
+def skipif(skip_condition, msg=None):
+    ''' Make function raise SkipTest exception if skip_condition is true
+
+    Parameters
+    ---------
+    skip_condition : bool
+        Flag to determine whether to skip test (True) or not (False)
+    msg : string
+        Message to give on raising a SkipTest exception
+    '''
+    if msg is None:
+        msg = 'Test skipped due to test condition (see code)'
+    def skip_decorator(f):
+        def skipper(*args, **kwargs):
+            if skip_condition:
+                raise nose.SkipTest, msg
+            else:
+                return f(*args, **kwargs)
+        return nose.tools.make_decorator(f)(skipper)
+    return skip_decorator

Modified: trunk/scipy/testing/utils.py
===================================================================
--- trunk/scipy/testing/utils.py	2008-01-19 19:43:04 UTC (rev 3852)
+++ trunk/scipy/testing/utils.py	2008-01-21 20:40:25 UTC (rev 3853)
@@ -1,10 +1,13 @@
 """Simple testing utilities
 """
 
-__all__ = ['set_local_path', 'restore_path', 'measure', 'info', 'warn', 'error']
+__all__ = ['set_local_path', 'restore_path', 'measure', 'info', 'warn',\
+           'error', 'decorate_methods']
 
 import os
 import sys
+import re
+from inspect import isfunction
 
 from numpy.distutils.misc_util import yellow_text, red_text
 from numpy.testing.utils import jiffies
@@ -58,3 +61,38 @@
 def error(message):
     print >> sys.stderr,red_text('Error: %s' % (message))
     sys.stderr.flush()
+
+def decorate_methods(cls, decorator, testmatch=None):
+    ''' Apply decorator to all methods in class matching testmatch
+
+    Parameters
+    ----------
+    cls : class
+        Class to decorate methods for
+    decorator : function
+        Decorator to apply to methods
+    testmatch : compiled regexp or string to compile to regexp
+        Decorators are applied if testmatch.search(methodname)
+        is not None.  Default value is
+        re.compile(r'(?:^|[\\b_\\.%s-])[Tt]est' % os.sep)
+        (the default for nose)
+    '''
+    if testmatch is None:
+        testmatch = re.compile(r'(?:^|[\\b_\\.%s-])[Tt]est' % os.sep)
+    else:
+        testmatch = re.compile(testmatch)
+    cls_attr = cls.__dict__
+    methods = filter(isfunction, cls_attr.values())
+    for function in methods:
+        try:
+            if hasattr(function, 'compat_func_name'):
+                funcname = function.compat_func_name
+            else:
+                funcname = function.__name__
+        except AttributeError:
+            # not a function
+            continue
+        if testmatch.search(funcname) and not funcname.startswith('_'):
+            setattr(cls, funcname, decorator(function))
+    return
+



More information about the Scipy-svn mailing list