[Numpy-svn] r3734 - in branches/multicore: . numpy numpy/core numpy/core/src numpy/core/tests numpy/distutils numpy/distutils/command numpy/distutils/fcompiler numpy/distutils/tests numpy/doc numpy/f2py numpy/testing

numpy-svn at scipy.org numpy-svn at scipy.org
Tue May 1 07:43:45 EDT 2007


Author: eric
Date: 2007-05-01 06:43:40 -0500 (Tue, 01 May 2007)
New Revision: 3734

Added:
   branches/multicore/numpy/distutils/tests/test_fcompiler_gnu.py
Modified:
   branches/multicore/
   branches/multicore/COMPATIBILITY
   branches/multicore/numpy/__init__.py
   branches/multicore/numpy/core/numeric.py
   branches/multicore/numpy/core/src/arrayobject.c
   branches/multicore/numpy/core/src/multiarraymodule.c
   branches/multicore/numpy/core/src/umathmodule.c.src
   branches/multicore/numpy/core/tests/test_multiarray.py
   branches/multicore/numpy/core/tests/test_regression.py
   branches/multicore/numpy/core/tests/test_umath.py
   branches/multicore/numpy/distutils/ccompiler.py
   branches/multicore/numpy/distutils/command/build_clib.py
   branches/multicore/numpy/distutils/command/build_ext.py
   branches/multicore/numpy/distutils/fcompiler/__init__.py
   branches/multicore/numpy/distutils/fcompiler/gnu.py
   branches/multicore/numpy/distutils/fcompiler/intel.py
   branches/multicore/numpy/distutils/fcompiler/vast.py
   branches/multicore/numpy/distutils/system_info.py
   branches/multicore/numpy/doc/DISTUTILS.txt
   branches/multicore/numpy/f2py/f90mod_rules.py
   branches/multicore/numpy/testing/numpytest.py
Log:
Merged revisions 3719-3733 via svnmerge from 
http://svn.scipy.org/svn/numpy/trunk

........
  r3720 | stefan | 2007-04-20 07:12:43 -0500 (Fri, 20 Apr 2007) | 2 lines
  
  Fix pointer size for F90 allocatable arrays on 64-bit platform. Closes ticket #147.
........
  r3721 | oliphant | 2007-04-20 15:27:01 -0500 (Fri, 20 Apr 2007) | 1 line
  
  Fix byte-swapping error on conversion to Object array from big-endian array (byte-swapping was happening twice in that case).  This fixes #503.
........
  r3722 | oliphant | 2007-04-21 23:29:42 -0500 (Sat, 21 Apr 2007) | 1 line
  
  Add loadtxt and savetxt adapted from matplotlib.
........
  r3723 | cookedm | 2007-04-22 15:57:58 -0500 (Sun, 22 Apr 2007) | 9 lines
  
  Better version handling for gnu and intel Fortran compilers
  
  - gnu compilers check if the version is >= 4, in which case it's gfortran
  - add a test file for gnu compiler check
  - simplify version matching on intel compilers to be more flexible
  - add FCompiler.find_executables so that subclasses can find executables
    at .customize() time, instead of when the class is created.
........
  r3724 | cookedm | 2007-04-22 16:12:57 -0500 (Sun, 22 Apr 2007) | 14 lines
  
  Some distutils work:
  
  - Add better support for C++ in numpy.distutils. Instead of munging the
    C compiler command, build_clib and build_ext call the new
    Compiler.cxx_compiler() method to get a version of the compiler suitable for
    C++ (this also takes care of the special needs of AIX).
  - If config_fc is specified in the Extension definition, merge that info
    instead of replacing it (otherwise, the name of the Fortran compiler is
    overwritten). This is done at the key level (ex., compiler options are
    replaced instead of appended).
  - clean up compiler.py a bit
  - clean up linking in build_ext
........
  r3725 | cookedm | 2007-04-22 16:18:20 -0500 (Sun, 22 Apr 2007) | 4 lines
  
  NumpyTest.test() takes an extra argument, all, which, if true, makes
  it act like NumpyTest.testall(). This comes from some refactoring to remove
  duplicate code in .test and .testall().
........
  r3726 | oliphant | 2007-04-24 14:15:33 -0500 (Tue, 24 Apr 2007) | 1 line
  
  Add patch to system_info for building with MKL on Win32 #504
........
  r3727 | oliphant | 2007-04-24 16:56:06 -0500 (Tue, 24 Apr 2007) | 1 line
  
  Restore invariant of (x == (x/y)*y + (x%y)) by making integer division with mixed-sign operands match Python.
........
  r3728 | cookedm | 2007-04-25 04:12:45 -0500 (Wed, 25 Apr 2007) | 2 lines
  
  Add test case for integer division
........
  r3729 | oliphant | 2007-04-27 15:37:55 -0500 (Fri, 27 Apr 2007) | 1 line
  
  Fix silly initialization of input variable.
........
  r3730 | stefan | 2007-04-30 03:53:00 -0500 (Mon, 30 Apr 2007) | 2 lines
  
  Add regression test.  Fix order of arguments in test_multiarray.
........
  r3731 | rkern | 2007-04-30 11:29:51 -0500 (Mon, 30 Apr 2007) | 1 line
  
  Fix typo.
........
  r3733 | jarrod.millman | 2007-05-01 00:59:49 -0500 (Tue, 01 May 2007) | 2 lines
  
  adding toc to distutils docs
........



Property changes on: branches/multicore
___________________________________________________________________
Name: svnmerge-integrated
   - /branches/distutils-revamp:1-2752 /trunk:1-3718
   + /branches/distutils-revamp:1-2752 /trunk:1-3733

Modified: branches/multicore/COMPATIBILITY
===================================================================
--- branches/multicore/COMPATIBILITY	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/COMPATIBILITY	2007-05-01 11:43:40 UTC (rev 3734)
@@ -15,7 +15,7 @@
 
 If you used typecode characters:
 
-'c' -> 'S1'
+'c' -> 'S1' or 'c'
 'b' -> 'B'
 '1' -> 'b'
 's' -> 'h'
@@ -35,12 +35,12 @@
 a->descr->zero       -->   PyArray_Zero(a)
 a->descr->one        -->   PyArray_One(a)
 
-Numeric/arrayobject.h  -->  numpy/arrayobject.h
+Numeric/arrayobject.h  -->  numpy/oldnumeric.h
 
 
 # These will actually work and are defines for PyArray_BYTE, 
 #   but you really should change it in your code
-PyArray_CHAR         -->  PyArray_BYTE  
+PyArray_CHAR         -->  PyArray_CHAR  
    (or PyArray_STRING which is more flexible)  
 PyArray_SBYTE        -->  PyArray_BYTE
 

Modified: branches/multicore/numpy/__init__.py
===================================================================
--- branches/multicore/numpy/__init__.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/__init__.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -84,11 +84,8 @@
 testing --> NumpyTest
 """
 
-    def test(level=1, verbosity=1):
-        if level <= 10:
-           return NumpyTest().test(level, verbosity)
-        else:
-           return NumpyTest().testall(level, verbosity)
+    def test(*args, **kw):
+        return NumpyTest().test(*args, **kw)
     test.__doc__ = NumpyTest.test.__doc__
 
     import add_newdocs

Modified: branches/multicore/numpy/core/numeric.py
===================================================================
--- branches/multicore/numpy/core/numeric.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/core/numeric.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -12,7 +12,7 @@
            'array_repr', 'array_str', 'set_string_function',
            'little_endian', 'require',
            'fromiter', 'array_equal', 'array_equiv',
-           'indices', 'fromfunction',
+           'indices', 'fromfunction', 'loadtxt', 'savetxt',
            'load', 'loads', 'isscalar', 'binary_repr', 'base_repr',
            'ones', 'identity', 'allclose', 'compare_chararrays', 'putmask',
            'seterr', 'geterr', 'setbufsize', 'getbufsize',
@@ -610,6 +610,177 @@
         file = _file(file,"rb")
     return _cload(file)
 
+# Adapted from matplotlib
+
+def _getconv(dtype):
+    typ = dtype.type
+    if issubclass(typ, bool_):
+        return lambda x: bool(int(x))
+    if issubclass(typ, integer):
+        return int
+    elif issubclass(typ, floating):
+        return float
+    elif issubclass(typ, complex):
+        return complex
+    else:
+        return str
+
+
+def _string_like(obj):
+    try: obj + ''
+    except (TypeError, ValueError): return 0
+    return 1
+
+def loadtxt(fname, dtype=float, comments='#', delimiter=None, converters=None,
+            skiprows=0, usecols=None, unpack=False):
+    """
+    Load ASCII data from fname into an array and return the array.
+
+    The data must be regular, same number of values in every row
+
+    fname can be a filename or a file handle.  Support for gzipped files is
+    automatic, if the filename ends in .gz
+
+    See scipy.loadmat to read and write matfiles.
+
+    Example usage:
+
+      X = loadtxt('test.dat')  # data in two columns
+      t = X[:,0]
+      y = X[:,1]
+
+    Alternatively, you can do the same with "unpack"; see below
+
+      X = loadtxt('test.dat')    # a matrix of data
+      x = loadtxt('test.dat')    # a single column of data
+
+
+    dtype - the data-type of the resulting array.  If this is a
+    record data-type, the the resulting array will be 1-d and each row will
+    be interpreted as an element of the array. The number of columns
+    used must match the number of fields in the data-type in this case. 
+    
+    comments - the character used to indicate the start of a comment
+    in the file
+
+    delimiter is a string-like character used to seperate values in the
+    file. If delimiter is unspecified or none, any whitespace string is
+    a separator.
+
+    converters, if not None, is a dictionary mapping column number to
+    a function that will convert that column to a float.  Eg, if
+    column 0 is a date string: converters={0:datestr2num}
+
+    skiprows is the number of rows from the top to skip
+
+    usecols, if not None, is a sequence of integer column indexes to
+    extract where 0 is the first column, eg usecols=(1,4,5) to extract
+    just the 2nd, 5th and 6th columns
+
+    unpack, if True, will transpose the matrix allowing you to unpack
+    into named arguments on the left hand side
+
+        t,y = load('test.dat', unpack=True) # for  two column data
+        x,y,z = load('somefile.dat', usecols=(3,5,7), unpack=True)
+
+    """
+
+    if _string_like(fname):
+        if fname.endswith('.gz'):
+            import gzip
+            fh = gzip.open(fname)
+        else:
+            fh = file(fname)
+    elif hasattr(fname, 'seek'):
+        fh = fname
+    else:
+        raise ValueError('fname must be a string or file handle')
+    X = []
+
+    dtype = multiarray.dtype(dtype)
+    defconv = _getconv(dtype)
+    converterseq = None    
+    if converters is None:
+        converters = {}
+        if dtype.names is not None:
+            converterseq = [_getconv(dtype.fields[name][0]) \
+                            for name in dtype.names]
+            
+    for i,line in enumerate(fh):
+        if i<skiprows: continue
+        line = line[:line.find(comments)].strip()
+        if not len(line): continue
+        vals = line.split(delimiter)
+        if converterseq is None:
+           converterseq = [converters.get(j,defconv) \
+                           for j in xrange(len(vals))]
+        if usecols is not None:
+            row = [converterseq[j](vals[j]) for j in usecols]
+        else:
+            row = [converterseq[j](val) for j,val in enumerate(vals)]
+        if dtype.names is not None:
+            row = tuple(row)
+        X.append(row)
+
+    X = array(X, dtype)
+    r,c = X.shape
+    if r==1 or c==1:
+        X.shape = max([r,c]),
+    if unpack: return X.T
+    else:  return X
+
+
+# adjust so that fmt can change across columns if desired. 
+
+def savetxt(fname, X, fmt='%.18e',delimiter=' '):
+    """
+    Save the data in X to file fname using fmt string to convert the
+    data to strings
+
+    fname can be a filename or a file handle.  If the filename ends in .gz,
+    the file is automatically saved in compressed gzip format.  The load()
+    command understands gzipped files transparently.
+
+    Example usage:
+
+    save('test.out', X)         # X is an array
+    save('test1.out', (x,y,z))  # x,y,z equal sized 1D arrays
+    save('test2.out', x)        # x is 1D
+    save('test3.out', x, fmt='%1.4e')  # use exponential notation
+
+    delimiter is used to separate the fields, eg delimiter ',' for
+    comma-separated values
+    """
+
+    if _string_like(fname):
+        if fname.endswith('.gz'):
+            import gzip
+            fh = gzip.open(fname,'wb')
+        else:
+            fh = file(fname,'w')
+    elif hasattr(fname, 'seek'):
+        fh = fname
+    else:
+        raise ValueError('fname must be a string or file handle')
+
+
+    X = asarray(X)
+    origShape = None
+    if len(X.shape)==1:
+        origShape = X.shape
+        X.shape = len(X), 1
+    for row in X:
+        fh.write(delimiter.join([fmt%val for val in row]) + '\n')
+
+    if origShape is not None:
+        X.shape = origShape
+
+
+    
+
+
+
+
 # These are all essentially abbreviations
 # These might wind up in a special abbreviations module
 

Modified: branches/multicore/numpy/core/src/arrayobject.c
===================================================================
--- branches/multicore/numpy/core/src/arrayobject.c	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/core/src/arrayobject.c	2007-05-01 11:43:40 UTC (rev 3734)
@@ -7732,12 +7732,18 @@
                 if (!PyArray_ISNUMBER(mp) && PyErr_Occurred()) return -1;
         }
 
-        /* If the input or output is STRING, UNICODE, or VOID */
+        /* If the input or output is OBJECT, STRING, UNICODE, or VOID */
         /*  then getitem and setitem are used for the cast */
         /*  and byteswapping is handled by those methods */
 
-        iswap = PyArray_ISBYTESWAPPED(mp) && !PyArray_ISFLEXIBLE(mp);
-        oswap = PyArray_ISBYTESWAPPED(out) && !PyArray_ISFLEXIBLE(out);
+        if (PyArray_ISFLEXIBLE(mp) || PyArray_ISOBJECT(mp) || PyArray_ISOBJECT(out) ||
+            PyArray_ISFLEXIBLE(out)) {
+                iswap = oswap = 0;
+        }
+        else {
+                iswap = PyArray_ISBYTESWAPPED(mp);
+                oswap = PyArray_ISBYTESWAPPED(out);
+        }
 
         return _broadcast_cast(out, mp, castfunc, iswap, oswap);
 }

Modified: branches/multicore/numpy/core/src/multiarraymodule.c
===================================================================
--- branches/multicore/numpy/core/src/multiarraymodule.c	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/core/src/multiarraymodule.c	2007-05-01 11:43:40 UTC (rev 3734)
@@ -3757,7 +3757,7 @@
         char *src, *dest;
         int copyret=0;
 
-        indices = ret = NULL;
+        indices = NULL;
 	self = (PyAO *)_check_axis(self0, &axis, CARRAY);
         if (self == NULL) return NULL;
 

Modified: branches/multicore/numpy/core/src/umathmodule.c.src
===================================================================
--- branches/multicore/numpy/core/src/umathmodule.c.src	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/core/src/umathmodule.c.src	2007-05-01 11:43:40 UTC (rev 3734)
@@ -1040,9 +1040,8 @@
 
 
 /**begin repeat
-#TYP=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG#
-#typ=char, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong#
-#otyp=float*4, double*6#
+#TYP=UBYTE,USHORT,UINT,ULONG,ULONGLONG#
+#typ=ubyte, ushort, uint, ulong, ulonglong#
 */
 static void
 @TYP at _divide(char **args, intp *dimensions, intp *steps, void *func)
@@ -1059,7 +1058,42 @@
 		}
 	}
 }
+/**end repeat**/
+
+
+/**begin repeat
+#TYP=BYTE,SHORT,INT,LONG,LONGLONG#
+#typ=char, short, int, long, longlong#
+*/
 static void
+ at TYP@_divide(char **args, intp *dimensions, intp *steps, void *func)
+{
+	register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
+	char *i1=args[0], *i2=args[1], *op=args[2];
+        @typ@ x, y, tmp;
+	for(i=0; i<n; i++, i1+=is1, i2+=is2, op+=os) {
+                y = *((@typ@ *)i2);
+		if (y == 0) {
+			generate_divbyzero_error();
+			*((@typ@ *)op)=0;
+		}
+		else {
+                        x = *((@typ@ *)i1);
+                        tmp = x / y;
+                        if (((x > 0) != (y > 0)) && (x % y != 0)) tmp--;
+                        *((@typ@ *)op)= tmp;
+		}
+	}
+}
+/**end repeat**/
+
+
+/**begin repeat
+#TYP=BYTE,UBYTE,SHORT,USHORT,INT,UINT,LONG,ULONG,LONGLONG,ULONGLONG#
+#typ=char, ubyte, short, ushort, int, uint, long, ulong, longlong, ulonglong#
+#otyp=float*4, double*6#
+*/
+static void
 @TYP at _true_divide(char **args, intp *dimensions, intp *steps, void *func)
 {
 	register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
@@ -1078,6 +1112,8 @@
 #define @TYP at _floor_divide @TYP at _divide
 /**end repeat**/
 
+
+
 /**begin repeat
 #TYP=FLOAT,DOUBLE,LONGDOUBLE#
 #typ=float,double,longdouble#

Modified: branches/multicore/numpy/core/tests/test_multiarray.py
===================================================================
--- branches/multicore/numpy/core/tests/test_multiarray.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/core/tests/test_multiarray.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -380,7 +380,7 @@
                     byteorder = '='
 
                 if x.dtype.byteorder == '|': byteorder = '|'
-                assert_equal(byteorder,x.dtype.byteorder)
+                assert_equal(x.dtype.byteorder,byteorder)
                 self._check_range(x,expected_min,expected_max)
         return x
 

Modified: branches/multicore/numpy/core/tests/test_regression.py
===================================================================
--- branches/multicore/numpy/core/tests/test_regression.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/core/tests/test_regression.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -645,5 +645,13 @@
         r = N.array([['abc']], dtype=[('var1', '|S20')])
         assert str(r['var1'][0][0]) == 'abc'
 
+    def check_take_output(self, level=rlevel):
+        """Ensure that 'take' honours output parameter."""
+        x = N.arange(12).reshape((3,4))
+        a = N.take(x,[0,2],axis=1)
+        b = N.zeros_like(a)
+        N.take(x,[0,2],axis=1,out=b)
+        assert_array_equal(a,b)
+
 if __name__ == "__main__":
     NumpyTest().run()

Modified: branches/multicore/numpy/core/tests/test_umath.py
===================================================================
--- branches/multicore/numpy/core/tests/test_umath.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/core/tests/test_umath.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -5,6 +5,14 @@
 from numpy import zeros, ndarray, array, choose
 restore_path()
 
+class test_division(NumpyTestCase):
+    def check_division_int(self):
+        # int division should return the floor of the result, a la Python
+        x = array([5, 10, 90, 100, -5, -10, -90, -100, -120])
+        assert_equal(x / 100, [0, 0, 0, 1, -1, -1, -1, -1, -2])
+        assert_equal(x // 100, [0, 0, 0, 1, -1, -1, -1, -1, -2])
+        assert_equal(x % 100, [5, 10, 90, 0, 95, 90, 10, 0, 80])
+
 class test_power(NumpyTestCase):
     def check_power_float(self):
         x = array([1., 2., 3.])

Modified: branches/multicore/numpy/distutils/ccompiler.py
===================================================================
--- branches/multicore/numpy/distutils/ccompiler.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/ccompiler.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -21,6 +21,10 @@
     distutils.sysconfig._config_vars['OPT'] = '-Wall -g -O0'
 #distutils.sysconfig._init_posix = _new_init_posix
 
+def replace_method(klass, method_name, func):
+    m = new.instancemethod(func, None, klass)
+    setattr(klass, method_name, m)
+
 # Using customized CCompiler.spawn.
 def CCompiler_spawn(self, cmd, display=None):
     if display is None:
@@ -37,8 +41,9 @@
         print o
         raise DistutilsExecError,\
               'Command "%s" failed with exit status %d' % (cmd, s)
-CCompiler.spawn = new.instancemethod(CCompiler_spawn,None,CCompiler)
 
+replace_method(CCompiler, 'spawn', CCompiler_spawn)
+
 def CCompiler_object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
     if output_dir is None:
         output_dir = ''
@@ -63,8 +68,7 @@
         obj_names.append(obj_name)
     return obj_names
 
-CCompiler.object_filenames = new.instancemethod(CCompiler_object_filenames,
-                                                None,CCompiler)
+replace_method(CCompiler, 'object_filenames', CCompiler_object_filenames)
 
 def CCompiler_compile(self, sources, output_dir=None, macros=None,
                       include_dirs=None, debug=0, extra_preargs=None,
@@ -114,7 +118,7 @@
     # Return *all* object filenames, not just the ones we just built.
     return objects
 
-CCompiler.compile = new.instancemethod(CCompiler_compile,None,CCompiler)
+replace_method(CCompiler, 'compile', CCompiler_compile)
 
 def CCompiler_customize_cmd(self, cmd):
     """ Customize compiler using distutils command.
@@ -139,8 +143,7 @@
         self.set_link_objects(cmd.link_objects)
     return
 
-CCompiler.customize_cmd = new.instancemethod(\
-    CCompiler_customize_cmd,None,CCompiler)
+replace_method(CCompiler, 'customize_cmd', CCompiler_customize_cmd)
 
 def _compiler_to_string(compiler):
     props = []
@@ -179,10 +182,8 @@
         print _compiler_to_string(self)
         print '*'*80
 
-CCompiler.show_customization = new.instancemethod(\
-    CCompiler_show_customization,None,CCompiler)
+replace_method(CCompiler, 'show_customization', CCompiler_show_customization)
 
-
 def CCompiler_customize(self, dist, need_cxx=0):
     # See FCompiler.customize for suggested usage.
     log.info('customize %s' % (self.__class__.__name__))
@@ -203,7 +204,7 @@
 
         if hasattr(self,'compiler') and self.compiler[0].find('cc')>=0:
             if not self.compiler_cxx:
-                if self.compiler[0][:3] == 'gcc':
+                if self.compiler[0].startswith('gcc'):
                     a, b = 'gcc', 'g++'
                 else:
                     a, b = 'cc', 'c++'
@@ -215,10 +216,23 @@
             log.warn('Missing compiler_cxx fix for '+self.__class__.__name__)
     return
 
-CCompiler.customize = new.instancemethod(\
-    CCompiler_customize,None,CCompiler)
+replace_method(CCompiler, 'customize', CCompiler_customize)
 
-def simple_version_match(pat=r'[-.\d]+', ignore=None, start=''):
+def simple_version_match(pat=r'[-.\d]+', ignore='', start=''):
+    """
+    Simple matching of version numbers, for use in CCompiler and FCompiler
+    classes.
+
+    :Parameters:
+        pat : regex matching version numbers.
+        ignore : false or regex matching expressions to skip over.
+        start : false or regex matching the start of where to start looking
+                for version numbers.
+
+    :Returns:
+        A function that is appropiate to use as the .version_match
+        attribute of a CCompiler class.
+    """
     def matcher(self, version_string):
         pos = 0
         if start:
@@ -271,15 +285,26 @@
     self.version = version
     return version
 
-CCompiler.get_version = new.instancemethod(\
-    CCompiler_get_version,None,CCompiler)
+replace_method(CCompiler, 'get_version', CCompiler_get_version)
 
+def CCompiler_cxx_compiler(self):
+    cxx = copy(self)
+    cxx.compiler_so = [cxx.compiler_cxx[0]] + cxx.compiler_so[1:]
+    if sys.platform.startswith('aix') and 'ld_so_aix' in cxx.linker_so[0]:
+        # AIX needs the ld_so_aix script included with Python
+        cxx.linker_so = [cxx.linker_so[0]] + cxx.compiler_cxx[0] \
+                        + cxx.linker_so[2:]
+    else:
+        cxx.linker_so = [cxx.compiler_cxx[0]] + cxx.linker_so[1:]
+    return cxx
+
+replace_method(CCompiler, 'cxx_compiler', CCompiler_cxx_compiler)
+
 compiler_class['intel'] = ('intelccompiler','IntelCCompiler',
                            "Intel C Compiler for 32-bit applications")
 compiler_class['intele'] = ('intelccompiler','IntelItaniumCCompiler',
                            "Intel C Itanium Compiler for Itanium-based applications")
-ccompiler._default_compilers = ccompiler._default_compilers \
-                               + (('linux.*','intel'),('linux.*','intele'))
+ccompiler._default_compilers += (('linux.*','intel'),('linux.*','intele'))
 
 if sys.platform == 'win32':
     compiler_class['mingw32'] = ('mingw32ccompiler', 'Mingw32CCompiler',

Modified: branches/multicore/numpy/distutils/command/build_clib.py
===================================================================
--- branches/multicore/numpy/distutils/command/build_clib.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/command/build_clib.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -21,13 +21,11 @@
     def initialize_options(self):
         old_build_clib.initialize_options(self)
         self.fcompiler = None
-        return
 
     def finalize_options(self):
         old_build_clib.finalize_options(self)
         self.set_undefined_options('build_ext',
                                    ('fcompiler', 'fcompiler'))
-        return
 
     def have_f_sources(self):
         for (lib_name, build_info) in self.libraries:
@@ -84,7 +82,6 @@
             self.fcompiler.show_customization()
 
         self.build_libraries(self.libraries)
-        return
 
     def get_source_files(self):
         self.check_library_list(self.libraries)
@@ -94,8 +91,6 @@
         return filenames
 
     def build_libraries(self, libraries):
-
-
         for (lib_name, build_info) in libraries:
             # default compilers
             compiler = self.compiler
@@ -109,8 +104,6 @@
                        "a list of source filenames") % lib_name
             sources = list(sources)
 
-
-
             lib_file = compiler.library_filename(lib_name,
                                                  output_dir=self.build_clib)
 
@@ -124,9 +117,9 @@
 
             config_fc = build_info.get('config_fc',{})
             if fcompiler is not None and config_fc:
-                log.info('using setup script specified config_fc '\
+                log.info('using additional config_fc from setup script '\
                          'for fortran compiler: %s' \
-                         % (config_fc))
+                         % (config_fc,))
                 from numpy.distutils.fcompiler import new_fcompiler
                 requiref90 = build_info.get('language','c')=='f90'
                 fcompiler = new_fcompiler(compiler=self.fcompiler.compiler_type,
@@ -134,7 +127,10 @@
                                           dry_run=self.dry_run,
                                           force=self.force,
                                           requiref90=requiref90)
-                fcompiler.customize(config_fc)
+                dist = self.distribution
+                base_config_fc = dist.get_option_dict('config_fc').copy()
+                base_config_fc.update(config_fc)
+                fcompiler.customize(base_config_fc)
 
             macros = build_info.get('macros')
             include_dirs = build_info.get('include_dirs')
@@ -165,19 +161,15 @@
 
             if cxx_sources:
                 log.info("compiling C++ sources")
-                old_compiler = self.compiler.compiler_so[0]
-                self.compiler.compiler_so[0] = self.compiler.compiler_cxx[0]
-
-                cxx_objects = compiler.compile(cxx_sources,
-                                               output_dir=self.build_temp,
-                                               macros=macros,
-                                               include_dirs=include_dirs,
-                                               debug=self.debug,
-                                               extra_postargs=extra_postargs)
+                cxx_compiler = compiler.cxx_compiler()
+                cxx_objects = cxx_compiler.compile(cxx_sources,
+                                                   output_dir=self.build_temp,
+                                                   macros=macros,
+                                                   include_dirs=include_dirs,
+                                                   debug=self.debug,
+                                                   extra_postargs=extra_postargs)
                 objects.extend(cxx_objects)
 
-                self.compiler.compiler_so[0] = old_compiler
-
             if f_sources:
                 log.info("compiling Fortran sources")
                 f_objects = fcompiler.compile(f_sources,
@@ -193,10 +185,8 @@
                                             debug=self.debug)
 
             clib_libraries = build_info.get('libraries',[])
-            for lname,binfo in libraries:
+            for lname, binfo in libraries:
                 if lname in clib_libraries:
                     clib_libraries.extend(binfo[1].get('libraries',[]))
             if clib_libraries:
                 build_info['libraries'] = clib_libraries
-
-        return

Modified: branches/multicore/numpy/distutils/command/build_ext.py
===================================================================
--- branches/multicore/numpy/distutils/command/build_ext.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/command/build_ext.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -201,17 +201,15 @@
         if cxx_sources:
             log.info("compiling C++ sources")
 
-            old_compiler = self.compiler.compiler_so[0]
-            self.compiler.compiler_so[0] = self.compiler.compiler_cxx[0]
+            cxx_compiler = self.compiler.cxx_compiler()
 
-            c_objects += self.compiler.compile(cxx_sources,
+            c_objects += cxx_compiler.compile(cxx_sources,
                                               output_dir=output_dir,
                                               macros=macros,
                                               include_dirs=include_dirs,
                                               debug=self.debug,
                                               extra_postargs=extra_args,
                                               **kws)
-            self.compiler.compiler_so[0] = old_compiler
 
         check_for_f90_modules = not not fmodule_sources
 
@@ -272,10 +270,7 @@
             objects.extend(ext.extra_objects)
         extra_args = ext.extra_link_args or []
 
-        try:
-            old_linker_so_0 = self.compiler.linker_so[0]
-        except:
-            pass
+        linker = self.compiler.link_shared_object
 
         use_fortran_linker = getattr(ext,'language','c') in ['f77','f90'] \
                              and self.fcompiler is not None
@@ -308,38 +303,31 @@
             if cxx_sources:
                 # XXX: Which linker should be used, Fortran or C++?
                 log.warn('mixing Fortran and C++ is untested')
-            link = self.fcompiler.link_shared_object
+            linker = self.fcompiler.link_shared_object
             language = ext.language or self.fcompiler.detect_language(f_sources)
         else:
-            link = self.compiler.link_shared_object
+            linker = self.compiler.link_shared_object
             if sys.version[:3]>='2.3':
                 language = ext.language or self.compiler.detect_language(sources)
             else:
                 language = ext.language
             if cxx_sources:
-                self.compiler.linker_so[0] = self.compiler.compiler_cxx[0]
+                linker = self.compiler.cxx_compiler().link_shared_object
 
         if sys.version[:3]>='2.3':
             kws = {'target_lang':language}
         else:
             kws = {}
 
-        link(objects, ext_filename,
-             libraries=self.get_libraries(ext) + c_libraries + clib_libraries,
-             library_dirs=ext.library_dirs + c_library_dirs + clib_library_dirs,
-             runtime_library_dirs=ext.runtime_library_dirs,
-             extra_postargs=extra_args,
-             export_symbols=self.get_export_symbols(ext),
-             debug=self.debug,
-             build_temp=self.build_temp,**kws)
+        linker(objects, ext_filename,
+               libraries=self.get_libraries(ext) + c_libraries + clib_libraries,
+               library_dirs=ext.library_dirs+c_library_dirs+clib_library_dirs,
+               runtime_library_dirs=ext.runtime_library_dirs,
+               extra_postargs=extra_args,
+               export_symbols=self.get_export_symbols(ext),
+               debug=self.debug,
+               build_temp=self.build_temp,**kws)
 
-        try:
-            self.compiler.linker_so[0] = old_linker_so_0
-        except:
-            pass
-
-        return
-
     def _libs_with_msvc_and_fortran(self, c_libraries, c_library_dirs):
         # Always use system linker when using MSVC compiler.
         f_lib_dirs = []

Modified: branches/multicore/numpy/distutils/fcompiler/__init__.py
===================================================================
--- branches/multicore/numpy/distutils/fcompiler/__init__.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/fcompiler/__init__.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -28,7 +28,7 @@
 
     Methods that subclasses may redefine:
 
-        get_version_cmd(), get_linker_so(), get_version()
+        find_executables(), get_version_cmd(), get_linker_so(), get_version()
         get_flags(), get_flags_opt(), get_flags_arch(), get_flags_debug()
         get_flags_f77(), get_flags_opt_f77(), get_flags_arch_f77(),
         get_flags_debug_f77(), get_flags_f90(), get_flags_opt_f90(),
@@ -113,6 +113,11 @@
     ## They are private to FCompiler class and may return unexpected
     ## results if used elsewhere. So, you have been warned..
 
+    def find_executables(self):
+        """Modify self.executables to hold found executables, instead of
+        searching for them at class creation time."""
+        pass
+
     def get_version_cmd(self):
         """ Compiler command to print out version information. """
         f77 = self.executables['compiler_f77']
@@ -267,6 +272,7 @@
             noarch = conf.get('noarch',[None,noopt])[1]
         debug = conf.get('debug',[None,0])[1]
 
+        self.find_executables()
 
         f77 = self.__get_cmd('compiler_f77','F77',(conf,'f77exec'))
         f90 = self.__get_cmd('compiler_f90','F90',(conf,'f90exec'))

Modified: branches/multicore/numpy/distutils/fcompiler/gnu.py
===================================================================
--- branches/multicore/numpy/distutils/fcompiler/gnu.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/fcompiler/gnu.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -4,7 +4,6 @@
 import warnings
 
 from numpy.distutils.cpuinfo import cpu
-from numpy.distutils.ccompiler import simple_version_match
 from numpy.distutils.fcompiler import FCompiler
 from numpy.distutils.exec_command import exec_command, find_executable
 from numpy.distutils.misc_util import mingw32, msvc_runtime_library
@@ -12,8 +11,32 @@
 class GnuFCompiler(FCompiler):
 
     compiler_type = 'gnu'
-    version_match = simple_version_match(start=r'GNU Fortran (?!95)')
 
+    def gnu_version_match(self, version_string):
+        """Handle the different versions of GNU fortran compilers"""
+        m = re.match(r'GNU Fortran', version_string)
+        if not m:
+            return None
+        m = re.match(r'GNU Fortran\s+95.*?([0-9-.]+)', version_string)
+        if m:
+            return ('gfortran', m.group(1))
+        m = re.match(r'GNU Fortran.*?([0-9-.]+)', version_string)
+        if m:
+            v = m.group(1)
+            if v.startswith('0') or v.startswith('2') or v.startswith('3'):
+                # the '0' is for early g77's
+                return ('g77', v)
+            else:
+                # at some point in the 4.x series, the ' 95' was dropped
+                # from the version string
+                return ('gfortran', v)
+
+    def version_match(self, version_string):
+        v = self.gnu_version_match(version_string)
+        if not v or v[0] != 'g77':
+            return None
+        return v[1]
+
     # 'g77 --version' results
     # SunOS: GNU Fortran (GCC 3.2) 3.2 20020814 (release)
     # Debian: GNU Fortran (GCC) 3.3.3 20040110 (prerelease) (Debian)
@@ -21,18 +44,15 @@
     #         GNU Fortran 0.5.25 20010319 (prerelease)
     # Redhat: GNU Fortran (GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
 
-    for fc_exe in map(find_executable,['g77','f77']):
-        if os.path.isfile(fc_exe):
-            break
     executables = {
-        'version_cmd'  : [fc_exe,"--version"],
-        'compiler_f77' : [fc_exe, "-g", "-Wall","-fno-second-underscore"],
+        'version_cmd'  : ["g77", "--version"],
+        'compiler_f77' : ["g77", "-g", "-Wall","-fno-second-underscore"],
         'compiler_f90' : None, # Use --fcompiler=gnu95 for f90 codes
         'compiler_fix' : None,
-        'linker_so'    : [fc_exe, "-g", "-Wall"],
+        'linker_so'    : ["g77", "-g", "-Wall"],
         'archiver'     : ["ar", "-cr"],
         'ranlib'       : ["ranlib"],
-        'linker_exe'   : [fc_exe, "-g", "-Wall"]
+        'linker_exe'   : ["g77", "-g", "-Wall"]
         }
     module_dir_switch = None
     module_include_switch = None
@@ -51,6 +71,13 @@
 
     suggested_f90_compiler = 'gnu95'
 
+    def find_executables(self):
+        for fc_exe in [find_executable(c) for c in ['g77','f77']]:
+            if os.path.isfile(fc_exe):
+                break
+        for key in ['version_cmd', 'compiler_f77', 'linker_so', 'linker_exe']:
+            self.executables[key][0] = fc_exe
+
     #def get_linker_so(self):
     #    # win32 linking should be handled by standard linker
     #    # Darwin g77 cannot be used as a linker.
@@ -218,12 +245,11 @@
         if gnu_ver >= '3.4.4':
             if cpu.is_PentiumM():
                 march_opt = '-march=pentium-m'
-        
         # Future:
         # if gnu_ver >= '4.3':
         #    if cpu.is_Core2():
         #        march_opt = '-march=core2'
-        
+
         # Note: gcc 3.2 on win32 has breakage with -march specified
         if '3.1.1' <= gnu_ver <= '3.4' and sys.platform=='win32':
             march_opt = ''
@@ -250,26 +276,32 @@
 class Gnu95FCompiler(GnuFCompiler):
 
     compiler_type = 'gnu95'
-    version_match = simple_version_match(start='GNU Fortran (95|\(GCC\))')
 
+    def version_match(self, version_string):
+        v = self.gnu_version_match(version_string)
+        if not v or v[0] != 'gfortran':
+            return None
+        return v[1]
+
     # 'gfortran --version' results:
+    # XXX is the below right?
     # Debian: GNU Fortran 95 (GCC 4.0.3 20051023 (prerelease) (Debian 4.0.2-3))
+    #         GNU Fortran 95 (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
     # OS X: GNU Fortran 95 (GCC) 4.1.0
     #       GNU Fortran 95 (GCC) 4.2.0 20060218 (experimental)
     #       GNU Fortran (GCC) 4.3.0 20070316 (experimental)
 
-    for fc_exe in map(find_executable,['gfortran','f95']):
-        if os.path.isfile(fc_exe):
-            break
     executables = {
-        'version_cmd'  : [fc_exe,"--version"],
-        'compiler_f77' : [fc_exe,"-Wall","-ffixed-form","-fno-second-underscore"],
-        'compiler_f90' : [fc_exe,"-Wall","-fno-second-underscore"],
-        'compiler_fix' : [fc_exe,"-Wall","-ffixed-form","-fno-second-underscore"],
-        'linker_so'    : [fc_exe,"-Wall"],
+        'version_cmd'  : ["gfortran", "--version"],
+        'compiler_f77' : ["gfortran", "-Wall", "-ffixed-form",
+                          "-fno-second-underscore"],
+        'compiler_f90' : ["gfortran", "-Wall", "-fno-second-underscore"],
+        'compiler_fix' : ["gfortran", "-Wall", "-ffixed-form",
+                          "-fno-second-underscore"],
+        'linker_so'    : ["gfortran", "-Wall"],
         'archiver'     : ["ar", "-cr"],
         'ranlib'       : ["ranlib"],
-        'linker_exe'   : [fc_exe,"-Wall"]
+        'linker_exe'   : ["gfortran", "-Wall"]
         }
 
     # use -mno-cygwin flag for g77 when Python is not Cygwin-Python
@@ -283,6 +315,14 @@
 
     g2c = 'gfortran'
 
+    def find_executables(self):
+        for fc_exe in [find_executable(c) for c in ['gfortran','f95']]:
+            if os.path.isfile(fc_exe):
+                break
+        for key in ['version_cmd', 'compiler_f77', 'compiler_f90',
+                    'compiler_fix', 'linker_so', 'linker_exe']:
+            self.executables[key][0] = fc_exe
+
     def get_libraries(self):
         opt = GnuFCompiler.get_libraries(self)
         if sys.platform == 'darwin':

Modified: branches/multicore/numpy/distutils/fcompiler/intel.py
===================================================================
--- branches/multicore/numpy/distutils/fcompiler/intel.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/fcompiler/intel.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -1,3 +1,6 @@
+# -*- encoding: iso-8859-1 -*-
+# above encoding b/c there's a non-ASCII character in the sample output
+# of intele
 # http://developer.intel.com/software/products/compilers/flin/
 
 import os
@@ -4,14 +7,18 @@
 import sys
 
 from numpy.distutils.cpuinfo import cpu
+from numpy.distutils.ccompiler import simple_version_match
 from numpy.distutils.fcompiler import FCompiler, dummy_fortran_file
 from numpy.distutils.exec_command import find_executable
 
+def intel_version_match(type):
+    # Match against the important stuff in the version string
+    return simple_version_match(start=r'Intel.*?Fortran.*?%s.*?Version' % (type,))
+
 class IntelFCompiler(FCompiler):
 
     compiler_type = 'intel'
-    version_pattern = r'Intel\(R\) Fortran Compiler for 32-bit '\
-                      'applications, Version (?P<version>[^\s*]*)'
+    version_match = intel_version_match('32-bit')
 
     for fc_exe in map(find_executable,['ifort','ifc']):
         if os.path.isfile(fc_exe):
@@ -74,10 +81,9 @@
 
 class IntelItaniumFCompiler(IntelFCompiler):
     compiler_type = 'intele'
-    version_pattern = r'Intel\(R\) Fortran (90 Compiler Itanium\(TM\)|Itanium\(R\)) Compiler'\
-                      ' for (the Itanium\(TM\)|Itanium\(R\))-based applications(,|)'\
-                      '\s+Version (?P<version>[^\s*]*)'
 
+    version_match = intel_version_match('Itanium')
+
 #Intel(R) Fortran Itanium(R) Compiler for Itanium(R)-based applications
 #Version 9.1    Build 20060928 Package ID: l_fc_c_9.1.039
 #Copyright (C) 1985-2006 Intel Corporation.  All rights reserved.
@@ -101,8 +107,7 @@
 class IntelEM64TFCompiler(IntelFCompiler):
     compiler_type = 'intelem'
 
-    version_pattern = r'Intel\(R\) Fortran Compiler for Intel\(R\) EM64T-based '\
-                      'applications, Version (?P<version>[^\s*]*)'
+    version_match = intel_version_match('EM64T-based')
 
     for fc_exe in map(find_executable,['ifort','efort','efc']):
         if os.path.isfile(fc_exe):
@@ -125,11 +130,13 @@
             opt.extend(['-tpp7', '-xW'])
         return opt
 
+# Is there no difference in the version string between the above compilers
+# and the Visual compilers?
+
 class IntelVisualFCompiler(FCompiler):
 
     compiler_type = 'intelv'
-    version_pattern = r'Intel\(R\) Fortran Compiler for 32-bit applications, '\
-                      'Version (?P<version>[^\s*]*)'
+    version_match = intel_version_match('32-bit')
 
     ar_exe = 'lib.exe'
     fc_exe = 'ifl'
@@ -181,9 +188,7 @@
 class IntelItaniumVisualFCompiler(IntelVisualFCompiler):
 
     compiler_type = 'intelev'
-    version_pattern = r'Intel\(R\) Fortran (90 Compiler Itanium\(TM\)|Itanium\(R\)) Compiler'\
-                      ' for (the Itanium\(TM\)|Itanium\(R\))-based applications(,|)'\
-                      '\s+Version (?P<version>[^\s*]*)'
+    version_match = intel_version_match('Itanium')
 
     fc_exe = 'efl' # XXX this is a wild guess
     ar_exe = IntelVisualFCompiler.ar_exe

Modified: branches/multicore/numpy/distutils/fcompiler/vast.py
===================================================================
--- branches/multicore/numpy/distutils/fcompiler/vast.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/fcompiler/vast.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -26,6 +26,9 @@
     module_dir_switch = None  #XXX Fix me
     module_include_switch = None #XXX Fix me
 
+    def find_executables(self):
+        pass
+
     def get_version_cmd(self):
         f90 = self.compiler_f90[0]
         d,b = os.path.split(f90)

Modified: branches/multicore/numpy/distutils/system_info.py
===================================================================
--- branches/multicore/numpy/distutils/system_info.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/distutils/system_info.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -811,9 +811,12 @@
         info = {}
         dict_append(info,**mkl)
         dict_append(info,
-                    libraries = ['pthread'],
                     define_macros=[('SCIPY_MKL_H',None)],
                     include_dirs = incl_dirs)
+        if sys.platform == 'win32':
+            pass # win32 has no pthread library
+        else:
+            dict_append(info, libraries=['pthread'])
         self.set_info(**info)
 
 class lapack_mkl_info(mkl_info):
@@ -822,7 +825,11 @@
         mkl = get_info('mkl')
         if not mkl:
             return
-        lapack_libs = self.get_libs('lapack_libs',['mkl_lapack32','mkl_lapack64'])
+        if sys.platform == 'win32':
+            lapack_libs = self.get_libs('lapack_libs',['mkl_lapack'])
+        else:
+            lapack_libs = self.get_libs('lapack_libs',['mkl_lapack32','mkl_lapack64'])
+            
         info = {'libraries': lapack_libs}
         dict_append(info,**mkl)
         self.set_info(**info)

Copied: branches/multicore/numpy/distutils/tests/test_fcompiler_gnu.py (from rev 3733, trunk/numpy/distutils/tests/test_fcompiler_gnu.py)

Modified: branches/multicore/numpy/doc/DISTUTILS.txt
===================================================================
--- branches/multicore/numpy/doc/DISTUTILS.txt	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/doc/DISTUTILS.txt	2007-05-01 11:43:40 UTC (rev 3734)
@@ -9,6 +9,8 @@
 :Revision: $LastChangedRevision$
 :SVN source: $HeadURL$
 
+.. contents::
+
 SciPy structure
 '''''''''''''''
 

Modified: branches/multicore/numpy/f2py/f90mod_rules.py
===================================================================
--- branches/multicore/numpy/f2py/f90mod_rules.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/f2py/f90mod_rules.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -24,6 +24,7 @@
 show=pprint.pprint
 
 from auxfuncs import *
+import numpy as N
 import capi_maps
 import cfuncs
 import rules
@@ -44,7 +45,8 @@
 fgetdims1 = """\
       external f2pysetdata
       logical ns
-      integer s(*),r,i,j
+      integer r,i,j
+      integer(%d) s(*)
       ns = .FALSE.
       if (allocated(d)) then
          do i=1,r
@@ -56,7 +58,7 @@
             deallocate(d)
          end if
       end if
-      if ((.not.allocated(d)).and.(s(1).ge.1)) then"""
+      if ((.not.allocated(d)).and.(s(1).ge.1)) then""" % N.intp().itemsize
 
 fgetdims2="""\
       end if

Modified: branches/multicore/numpy/testing/numpytest.py
===================================================================
--- branches/multicore/numpy/testing/numpytest.py	2007-05-01 05:59:49 UTC (rev 3733)
+++ branches/multicore/numpy/testing/numpytest.py	2007-05-01 11:43:40 UTC (rev 3734)
@@ -11,7 +11,7 @@
 __all__ = ['set_package_path', 'set_local_path', 'restore_path',
            'IgnoreException', 'NumpyTestCase', 'NumpyTest',
            'ScipyTestCase', 'ScipyTest', # for backward compatibility
-           'importall'
+           'importall',
            ]
 
 DEBUG=0
@@ -338,7 +338,7 @@
         short_module_name = self._rename_map.get(short_module_name,short_module_name)
         return short_module_name
 
-    def _get_module_tests(self,module,level,verbosity):
+    def _get_module_tests(self, module, level, verbosity):
         mstr = self._module_str
 
         short_module_name = self._get_short_module_name(module)
@@ -395,9 +395,8 @@
 
     def _get_suite_list(self, test_module, level, module_name='__main__',
                         verbosity=1):
-        mstr = self._module_str
         suite_list = []
-        if hasattr(test_module,'test_suite'):
+        if hasattr(test_module, 'test_suite'):
             suite_list.extend(test_module.test_suite(level)._tests)
         for name in dir(test_module):
             obj = getattr(test_module, name)
@@ -410,44 +409,14 @@
                 if getattr(suite,'isrunnable',lambda mthname:1)(mthname):
                     suite_list.append(suite)
         if verbosity>=0:
-            self.info('  Found %s tests for %s' % (len(suite_list),module_name))
+            self.info('  Found %s tests for %s' % (len(suite_list), module_name))
         return suite_list
 
-    def test(self,level=1,verbosity=1):
-        """ Run Numpy module test suite with level and verbosity.
-
-        level:
-          None           --- do nothing, return None
-          < 0            --- scan for tests of level=abs(level),
-                             don't run them, return TestSuite-list
-          > 0            --- scan for tests of level, run them,
-                             return TestRunner
-
-        verbosity:
-          >= 0           --- show information messages
-          > 1            --- show warnings on missing tests
-
-        It is assumed that package tests suite follows the following
-        convention: for each package module, there exists file
-        <packagepath>/tests/test_<modulename>.py that defines
-        TestCase classes (with names having prefix 'test_') with methods
-        (with names having prefixes 'check_' or 'bench_'); each of
-        these methods are called when running unit tests.
-        """
-        if level is None: # Do nothing.
-            return
-
-        if isinstance(self.package, str):
-            exec 'import %s as this_package' % (self.package)
-        else:
-            this_package = self.package
-
+    def _test_suite_from_modules(self, this_package, level, verbosity):
         package_name = this_package.__name__
-
         modules = []
         for name, module in sys.modules.items():
-            if package_name != name[:len(package_name)] \
-                   or module is None:
+            if not name.startswith(package_name) or module is None:
                 continue
             if not hasattr(module,'__file__'):
                 continue
@@ -465,59 +434,18 @@
 
         suites.extend(self._get_suite_list(sys.modules[package_name],
                                            abs(level), verbosity=verbosity))
+        return unittest.TestSuite(suites)
 
-        all_tests = unittest.TestSuite(suites)
-        if level<0:
-            return all_tests
-
-        runner = unittest.TextTestRunner(verbosity=verbosity)
-        # Use the builtin displayhook. If the tests are being run
-        # under IPython (for instance), any doctest test suites will
-        # fail otherwise.
-        old_displayhook = sys.displayhook
-        sys.displayhook = sys.__displayhook__
-        try:
-            runner.run(all_tests)
-        finally:
-            sys.displayhook = old_displayhook
-        return runner
-
-    def testall(self,level=1,verbosity=1):
-        """ Run Numpy module test suite with level and verbosity.
-
-        level:
-          None           --- do nothing, return None
-          < 0            --- scan for tests of level=abs(level),
-                             don't run them, return TestSuite-list
-          > 0            --- scan for tests of level, run them,
-                             return TestRunner
-
-        verbosity:
-          >= 0           --- show information messages
-          > 1            --- show warnings on missing tests
-
-        Different from .test(..) method, this method looks for
-        TestCase classes from all files in <packagedir>/tests/
-        directory and no assumptions are made for naming the
-        TestCase classes or their methods.
-        """
-        if level is None: # Do nothing.
-            return
-
-        if isinstance(self.package, str):
-            exec 'import %s as this_package' % (self.package)
-        else:
-            this_package = self.package
+    def _test_suite_from_all_tests(self, this_package, level, verbosity):
+        importall(this_package)
         package_name = this_package.__name__
 
-        importall(this_package)
-
+        # Find all tests/ directories under the package
         test_dirs_names = {}
         for name, module in sys.modules.items():
-            if package_name != name[:len(package_name)] \
-                   or module is None:
+            if not name.startswith(package_name) or module is None:
                 continue
-            if not hasattr(module,'__file__'):
+            if not hasattr(module, '__file__'):
                 continue
             d = os.path.dirname(module.__file__)
             if os.path.basename(d)=='tests':
@@ -532,8 +460,10 @@
         test_dirs = test_dirs_names.keys()
         test_dirs.sort()
 
+        # For each file in each tests/ directory with a test case in it,
+        # import the file, and add the test cases to our list
         suite_list = []
-        testcase_match = re.compile(r'\s*class\s+[_\w]+\s*\(.*TestCase').match
+        testcase_match = re.compile(r'\s*class\s+\w+\s*\(.*TestCase').match
         for test_dir in test_dirs:
             test_dir_module = test_dirs_names[test_dir]
 
@@ -547,9 +477,9 @@
                 f = os.path.join(test_dir, fn)
 
                 # check that file contains TestCase class definitions:
-                fid = open(f)
+                fid = open(f, 'r')
                 skip = True
-                for line in fid.readlines():
+                for line in fid:
                     if testcase_match(line):
                         skip = False
                         break
@@ -559,31 +489,73 @@
 
                 # import the test file
                 n = test_dir_module + '.' + base
-                sys.path.insert(0,test_dir) # in case test files import local modules
+                # in case test files import local modules
+                sys.path.insert(0, test_dir)
+                fo = None
                 try:
-                    test_module = imp.load_module(n,
-                                                  open(f),
-                                                  f,
-                                                  ('.py', 'U', 1))
-                except Exception, msg:
-                    print 'Failed importing %s: %s' % (f,msg)
+                    try:
+                        fo = open(f)
+                        test_module = imp.load_module(n, fo, f,
+                                                      ('.py', 'U', 1))
+                    except Exception, msg:
+                        print 'Failed importing %s: %s' % (f,msg)
+                        continue
+                finally:
+                    if fo:
+                        fo.close()
                     del sys.path[0]
-                    continue
-                del sys.path[0]
 
-                for name in dir(test_module):
-                    obj = getattr(test_module, name)
-                    if type(obj) is not type(unittest.TestCase) \
-                           or not issubclass(obj, unittest.TestCase) \
-                           or not self.check_testcase_name(obj.__name__):
-                        continue
-                    for mthname in self._get_method_names(obj,abs(level)):
-                        suite = obj(mthname)
-                        if getattr(suite,'isrunnable',lambda mthname:1)(mthname):
-                            suite_list.append(suite)
+                suites = self._get_suite_list(test_module, level,
+                                              module_name=n,
+                                              verbosity=verbosity)
+                suite_list.extend(suites)
 
         all_tests = unittest.TestSuite(suite_list)
-        if level<0:
+        return all_tests
+
+    def test(self, level=1, verbosity=1, all=False):
+        """Run Numpy module test suite with level and verbosity.
+
+        level:
+          None           --- do nothing, return None
+          < 0            --- scan for tests of level=abs(level),
+                             don't run them, return TestSuite-list
+          > 0            --- scan for tests of level, run them,
+                             return TestRunner
+          > 10           --- run all tests (same as specifying all=True).
+                             (backward compatibility).
+
+        verbosity:
+          >= 0           --- show information messages
+          > 1            --- show warnings on missing tests
+
+        all:
+          True            --- run all test files (like self.testall())
+          False (default) --- only run test files associated with a module
+
+        It is assumed (when all=False) that package tests suite follows the
+        following convention: for each package module, there exists file
+        <packagepath>/tests/test_<modulename>.py that defines TestCase classes
+        (with names having prefix 'test_') with methods (with names having
+        prefixes 'check_' or 'bench_'); each of these methods are called when
+        running unit tests.
+        """
+        if level is None: # Do nothing.
+            return
+
+        if isinstance(self.package, str):
+            exec 'import %s as this_package' % (self.package)
+        else:
+            this_package = self.package
+
+        if all:
+            all_tests = self._test_suite_from_all_tests(this_package,
+                                                        level, verbosity)
+        else:
+            all_tests = self._test_suite_from_modules(this_package,
+                                                      level, verbosity)
+
+        if level < 0:
             return all_tests
 
         runner = unittest.TextTestRunner(verbosity=verbosity)
@@ -598,6 +570,27 @@
             sys.displayhook = old_displayhook
         return runner
 
+    def testall(self, level=1,verbosity=1):
+        """ Run Numpy module test suite with level and verbosity.
+
+        level:
+          None           --- do nothing, return None
+          < 0            --- scan for tests of level=abs(level),
+                             don't run them, return TestSuite-list
+          > 0            --- scan for tests of level, run them,
+                             return TestRunner
+
+        verbosity:
+          >= 0           --- show information messages
+          > 1            --- show warnings on missing tests
+
+        Different from .test(..) method, this method looks for
+        TestCase classes from all files in <packagedir>/tests/
+        directory and no assumptions are made for naming the
+        TestCase classes or their methods.
+        """
+        return self.test(level=level, verbosity=verbosity, all=True)
+
     def run(self):
         """ Run Numpy module test suite with level and verbosity
         taken from sys.argv. Requires optparse module.




More information about the Numpy-svn mailing list