[yt-svn] commit/yt-3.0: 42 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Mon Aug 26 11:40:15 PDT 2013


42 new commits in yt-3.0:

https://bitbucket.org/yt_analysis/yt-3.0/commits/940b5818b005/
Changeset:   940b5818b005
Branch:      yt
User:        jzuhone
Date:        2013-08-19 16:44:24
Summary:     Convert Athena data to 64-bits after reading
Affected #:  1 file

diff -r 697fea2926724910a0de7cbd1910f00789db46c7 -r 940b5818b00593ea5aec3f637592770c368ff0cb yt/frontends/athena/io.py
--- a/yt/frontends/athena/io.py
+++ b/yt/frontends/athena/io.py
@@ -68,9 +68,9 @@
                 data = data[2::3].reshape(grid_dims,order='F').copy()
         f.close()
         if grid.pf.field_ordering == 1:
-            return data.T
+            return data.T.astype("float64")
         else:
-            return data
+            return data.astype("float64")
 
     def _read_data_slice(self, grid, field, axis, coord):
         sl = [slice(None), slice(None), slice(None)]


https://bitbucket.org/yt_analysis/yt-3.0/commits/622c23da642d/
Changeset:   622c23da642d
Branch:      yt
User:        MatthewTurk
Date:        2013-08-19 17:03:29
Summary:     Merged in jzuhone/yt-athena (pull request #573)

Convert Athena data to 64-bits after reading
Affected #:  1 file

diff -r 0bd09ebbc6c1fd8fac4a7ef51c5ae154664c3658 -r 622c23da642d4f1d56f61cde3386ef60e2b4e158 yt/frontends/athena/io.py
--- a/yt/frontends/athena/io.py
+++ b/yt/frontends/athena/io.py
@@ -68,9 +68,9 @@
                 data = data[2::3].reshape(grid_dims,order='F').copy()
         f.close()
         if grid.pf.field_ordering == 1:
-            return data.T
+            return data.T.astype("float64")
         else:
-            return data
+            return data.astype("float64")
 
     def _read_data_slice(self, grid, field, axis, coord):
         sl = [slice(None), slice(None), slice(None)]


https://bitbucket.org/yt_analysis/yt-3.0/commits/fe8d9d1ca9dc/
Changeset:   fe8d9d1ca9dc
Branch:      yt
User:        brittonsmith
Date:        2013-08-19 20:28:43
Summary:     Fixing convention in install script that only works for bash version
greater than 4.0.
Affected #:  1 file

diff -r 622c23da642d4f1d56f61cde3386ef60e2b4e158 -r fe8d9d1ca9dc381ac971396b1382c659101e8c0a doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -832,7 +832,7 @@
 	    echo "Building BLAS"
 	    cd BLAS
 	    gfortran -O2 -fPIC -fno-second-underscore -c *.f
-	    ar r libfblas.a *.o &>> ${LOG_FILE}
+	    ar r libfblas.a *.o 1>> ${LOG_FILE}
 	    ranlib libfblas.a 1>> ${LOG_FILE}
 	    rm -rf *.o
 	    touch done


https://bitbucket.org/yt_analysis/yt-3.0/commits/231b982b4c13/
Changeset:   231b982b4c13
Branch:      yt
User:        MatthewTurk
Date:        2013-08-19 20:44:31
Summary:     Quick fix, from Nathan.
Affected #:  1 file

diff -r fe8d9d1ca9dc381ac971396b1382c659101e8c0a -r 231b982b4c13612f1f040cad074b5e1e39f883ad doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -832,7 +832,7 @@
 	    echo "Building BLAS"
 	    cd BLAS
 	    gfortran -O2 -fPIC -fno-second-underscore -c *.f
-	    ar r libfblas.a *.o 1>> ${LOG_FILE}
+	    ar r libfblas.a *.o 2>> ${LOG_FILE}
 	    ranlib libfblas.a 1>> ${LOG_FILE}
 	    rm -rf *.o
 	    touch done


https://bitbucket.org/yt_analysis/yt-3.0/commits/5cd76d510e52/
Changeset:   5cd76d510e52
Branch:      yt
User:        ngoldbaum
Date:        2013-08-19 22:06:58
Summary:     Fixing all instances of bad redirections.
Affected #:  1 file

diff -r 231b982b4c13612f1f040cad074b5e1e39f883ad -r 5cd76d510e52558fdbdff615e0a904a8d352a673 doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -832,8 +832,8 @@
 	    echo "Building BLAS"
 	    cd BLAS
 	    gfortran -O2 -fPIC -fno-second-underscore -c *.f
-	    ar r libfblas.a *.o 2>> ${LOG_FILE}
-	    ranlib libfblas.a 1>> ${LOG_FILE}
+	    ( ar r libfblas.a *.o 2>&1 ) 1>> ${LOG_FILE}
+	    ( ranlib libfblas.a 2>&1 ) 1>> ${LOG_FILE}
 	    rm -rf *.o
 	    touch done
 	    cd ..
@@ -844,7 +844,7 @@
 	    echo "Building LAPACK"
 	    cd $LAPACK/
 	    cp INSTALL/make.inc.gfortran make.inc
-	    make lapacklib OPTS="-fPIC -O2" NOOPT="-fPIC -O0" CFLAGS=-fPIC LDFLAGS=-fPIC 1>> ${LOG_FILE} || do_exit
+	    ( make lapacklib OPTS="-fPIC -O2" NOOPT="-fPIC -O0" CFLAGS=-fPIC LDFLAGS=-fPIC 2>&1 ) 1>> ${LOG_FILE} || do_exit
 	    touch done
 	    cd ..
 	fi
@@ -943,10 +943,10 @@
 touch done
 cd $MY_PWD
 
-if !(${DEST_DIR}/bin/python2.7 -c "import readline" >> ${LOG_FILE})
+if !( ( ${DEST_DIR}/bin/python2.7 -c "import readline" 2>&1 )>> ${LOG_FILE})
 then
     echo "Installing pure-python readline"
-    ${DEST_DIR}/bin/pip install readline 1>> ${LOG_FILE}
+    ( ${DEST_DIR}/bin/pip install readline 2>&1 ) 1>> ${LOG_FILE}
 fi
 
 if [ $INST_ENZO -eq 1 ]


https://bitbucket.org/yt_analysis/yt-3.0/commits/4df4b2384df2/
Changeset:   4df4b2384df2
Branch:      yt
User:        chummels
Date:        2013-05-23 17:48:11
Summary:     Correcting a bug in the docstrings for Halo finding.
Affected #:  1 file

diff -r 0a8cfd079b16aee3250d5c5f7ab5eaa4f16fd5d0 -r 4df4b2384df29ac05e882be9203d46c1b75b8029 yt/analysis_modules/halo_finding/halo_objects.py
--- a/yt/analysis_modules/halo_finding/halo_objects.py
+++ b/yt/analysis_modules/halo_finding/halo_objects.py
@@ -2451,7 +2451,7 @@
         The density threshold used when building halos. Default = 160.0.
     dm_only : bool
         If True, only dark matter particles are used when building halos.
-        Default = False.
+        Default = True.
     padding : float
         When run in parallel, the finder needs to surround each subvolume
         with duplicated particles for halo finidng to work. This number


https://bitbucket.org/yt_analysis/yt-3.0/commits/9df6cc432550/
Changeset:   9df6cc432550
Branch:      yt
User:        chummels
Date:        2013-05-23 17:50:56
Summary:     Fixing several docstring inaccuracies in halo finding.
Affected #:  1 file

diff -r 4df4b2384df29ac05e882be9203d46c1b75b8029 -r 9df6cc43255087eca90dcba2974d02d8c03b9eac yt/analysis_modules/halo_finding/halo_objects.py
--- a/yt/analysis_modules/halo_finding/halo_objects.py
+++ b/yt/analysis_modules/halo_finding/halo_objects.py
@@ -1062,8 +1062,9 @@
     def __init__(self, data_source, dm_only=True, redshift=-1):
         """
         Run hop on *data_source* with a given density *threshold*.  If
-        *dm_only* is set, only run it on the dark matter particles, otherwise
-        on all particles.  Returns an iterable collection of *HopGroup* items.
+        *dm_only* is True (default), only run it on the dark matter particles, 
+        otherwise on all particles.  Returns an iterable collection of 
+        *HopGroup* items.
         """
         self._data_source = data_source
         self.dm_only = dm_only
@@ -1458,7 +1459,7 @@
 class HOPHaloList(HaloList):
     """
     Run hop on *data_source* with a given density *threshold*.  If
-    *dm_only* is set, only run it on the dark matter particles, otherwise
+    *dm_only* is True (default), only run it on the dark matter particles, otherwise
     on all particles.  Returns an iterable collection of *HopGroup* items.
     """
     _name = "HOP"
@@ -1657,7 +1658,7 @@
 class parallelHOPHaloList(HaloList, ParallelAnalysisInterface):
     """
     Run hop on *data_source* with a given density *threshold*.  If
-    *dm_only* is set, only run it on the dark matter particles, otherwise
+    *dm_only* is True (default), only run it on the dark matter particles, otherwise
     on all particles.  Returns an iterable collection of *HopGroup* items.
     """
     _name = "parallelHOP"
@@ -2122,7 +2123,7 @@
         The density threshold used when building halos. Default = 160.0.
     dm_only : bool
         If True, only dark matter particles are used when building halos.
-        Default = False.
+        Default = True.
     resize : bool
         Turns load-balancing on or off. Default = True.
     kdtree : string
@@ -2556,7 +2557,7 @@
         applied.  Default = 0.2.
     dm_only : bool
         If True, only dark matter particles are used when building halos.
-        Default = False.
+        Default = True.
     padding : float
         When run in parallel, the finder needs to surround each subvolume
         with duplicated particles for halo finidng to work. This number


https://bitbucket.org/yt_analysis/yt-3.0/commits/cfbecf7f8933/
Changeset:   cfbecf7f8933
Branch:      yt
User:        chummels
Date:        2013-08-15 02:49:29
Summary:     Adding shaded_levels keyword to annotate_grids command for the plot window interface.  This allows for different grid levels to be differentiated by color in the overplot boxes.
Affected #:  1 file

diff -r f936432ed45df5f59f1691ec56f64ee31bb85a46 -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -337,18 +337,29 @@
 
 class GridBoundaryCallback(PlotCallback):
     """
-    annotate_grids(alpha=1.0, min_pix=1, draw_ids=False, periodic=True)
+    annotate_grids(alpha=1.0, min_pix=1, min_pix_ids=20, draw_ids=False, 
+                   periodic=True, min_level=None, max_level=None, 
+                   shaded_levels=False)
 
-    Adds grid boundaries to a plot, optionally with *alpha*-blending.
-    Cuttoff for display is at *min_pix* wide.
-    *draw_ids* puts the grid id in the corner of the grid.  (Not so great in projections...)
-    Grids must be wider than *min_pix_ids* otherwise the ID will not be drawn.  If *min_level* 
-    is specified, only draw grids at or above min_level.  If *max_level* is specified, only 
-    draw grids at or below max_level.
+    Overplots grid boundaries on a plot, optionally with *alpha*-blending.
+    Cutoff for display is at *min_pix* width.  
+
+    *draw_ids* puts the grid id in the corner of each grid.  
+    (Not so great in projections...)
+
+    Grids must be wider than *min_pix_ids* otherwise the ID will not be drawn.  
+    
+    If *min_level* is specified, only draw grids at or above min_level.  
+    
+    If *max_level* is specified, only draw grids at or below max_level.
+
+    If *shaded_levels* is True, then differentiate between different levels
+    of refinement with different shades of white/gray/black, with white
+    as the lowest level and black as the highest level of refinement.
     """
     _type_name = "grids"
     def __init__(self, alpha=1.0, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
-                 min_level=None, max_level=None):
+                 min_level=None, max_level=None, shaded_levels=False):
         PlotCallback.__init__(self)
         self.alpha = alpha
         self.min_pix = min_pix
@@ -357,6 +368,7 @@
         self.periodic = periodic
         self.min_level = min_level
         self.max_level = max_level
+        self.shaded_levels = shaded_levels
 
     def __call__(self, plot):
         x0, x1 = plot.xlim
@@ -399,16 +411,34 @@
             verts = np.array(
                 [(left_edge_x, left_edge_x, right_edge_x, right_edge_x),
                  (left_edge_y, right_edge_y, right_edge_y, left_edge_y)])
-            verts=verts.transpose()[visible,:,:]
-            edgecolors = (0.0,0.0,0.0,self.alpha)
-            grid_collection = matplotlib.collections.PolyCollection(
-                verts, facecolors="none",
-                edgecolors=edgecolors)
-            plot._axes.hold(True)
-            plot._axes.add_collection(grid_collection)
+            if not self.shaded_levels:
+                verts=verts.transpose()[visible,:,:]
+                edgecolors = (0.0,0.0,0.0,self.alpha)
+                grid_collection = matplotlib.collections.PolyCollection(
+                    verts, facecolors="none",
+                    edgecolors=edgecolors)
+                plot._axes.hold(True)
+                plot._axes.add_collection(grid_collection)
+            # if shaded_levels is defined, then make the different
+            # grid boxes different colors.  lowest level of resolution
+            # is white and go up in shades of gray to highest level
+            # of resolution which is black.
+            else:
+                level_range = max_level - min_level
+                for j,level in enumerate(range(min_level, max_level+1)):
+                    edge_shade = 1-(j*(1./level_range))
+                    edgecolors = (edge_shade, edge_shade, edge_shade, self.alpha)
+                    one_level =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix ) & \
+                                 ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix ) & \
+                                 ( grid_levels == level)
+                    grid_collection = matplotlib.collections.PolyCollection(
+                                      verts.transpose()[one_level,:,:], facecolors="none",
+                                      edgecolors=edgecolors)
+                    plot._axes.hold(True)
+                    plot._axes.add_collection(grid_collection)
             if self.draw_ids:
                 visible_ids =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix_ids ) & \
-                               ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix_ids )
+                               ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix_ids ) 
                 active_ids = np.unique(plot.data['GridIndices'])
                 for i in np.where(visible_ids)[0]:
                     plot._axes.text(


https://bitbucket.org/yt_analysis/yt-3.0/commits/b17c65836c1d/
Changeset:   b17c65836c1d
Branch:      yt
User:        chummels
Date:        2013-08-15 03:02:40
Summary:     Merging with tip.
Affected #:  18 files

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
 include distribute_setup.py README* CREDITS FUNDING LICENSE.txt
 recursive-include yt/gui/reason/html *.html *.png *.ico *.js
 recursive-include yt *.pyx *.pxd *.hh *.h README*
+recursive-include yt/utilities/kdtree *.f90 *.v Makefile LICENSE
\ No newline at end of file

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/__init__.py
--- a/yt/__init__.py
+++ b/yt/__init__.py
@@ -96,7 +96,7 @@
     if answer_big_data:
         nose_argv.append('--answer-big-data')
     log_suppress = ytcfg.getboolean("yt","suppressStreamLogging")
-    ytcfg["yt","suppressStreamLogging"] = 'True'
+    ytcfg.set("yt","suppressStreamLogging", 'True')
     initial_dir = os.getcwd()
     yt_file = os.path.abspath(__file__)
     yt_dir = os.path.dirname(yt_file)
@@ -105,4 +105,4 @@
         nose.run(argv=nose_argv)
     finally:
         os.chdir(initial_dir)
-        ytcfg["yt","suppressStreamLogging"] = log_suppress
+        ytcfg.set("yt","suppressStreamLogging", str(log_suppress))

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
--- /dev/null
+++ b/yt/analysis_modules/absorption_spectrum/absorption_spectrum_fit.py
@@ -0,0 +1,809 @@
+from scipy import optimize
+import numpy as na
+import h5py
+from yt.analysis_modules.absorption_spectrum.absorption_line \
+        import voigt
+
+
+def generate_total_fit(x, fluxData, orderFits, speciesDicts, 
+        minError=1E-5, complexLim=.999,
+        fitLim=.99, minLength=3, 
+        maxLength=1000, splitLim=.99,
+        output_file=None):
+
+    """
+    This function is designed to fit an absorption spectrum by breaking 
+    the spectrum up into absorption complexes, and iteratively adding
+    and optimizing voigt profiles to each complex.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        1d array of wavelengths
+    fluxData : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    orderFits : list
+        list of the names of the species in the order that they 
+        should be fit. Names should correspond to the names of the species
+        given in speciesDicts. (ex: ['lya','OVI'])
+    speciesDicts : dictionary
+        Dictionary of dictionaries (I'm addicted to dictionaries, I
+        confess). Top level keys should be the names of all the species given
+        in orderFits. The entries should be dictionaries containing all 
+        relevant parameters needed to create an absorption line of a given 
+        species (f,Gamma,lambda0) as well as max and min values for parameters
+        to be fit
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+    output_file : string, optional
+        location to save the results of the fit. 
+
+    Returns
+    -------
+    allSpeciesLines : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. (ie: N[0],b[0],z[0] will create a line that
+        fits some part of the absorption spectrum). 'group#' is a similar list
+        but identifies which absorbing complex each line belongs to. Lines
+        with the same group# were fit at the same time. group#'s do not
+        correlate between species (ie: an lya line with group number 1 and
+        an OVI line with group number 1 were not fit together and do
+        not necessarily correspond to the same region)
+    yFit : (N) ndarray
+        array of flux corresponding to the combination of all fitted
+        absorption profiles. Same size as x.
+    """
+
+    #Empty dictionary for fitted lines
+    allSpeciesLines = {}
+
+    #Wavelength of beginning of array, wavelength resolution
+    x0,xRes=x[0],x[1]-x[0]
+
+    #Empty fit without any lines
+    yFit = na.ones(len(fluxData))
+
+    #Find all regions where lines/groups of lines are present
+    cBounds = _find_complexes(x, fluxData, fitLim=fitLim,
+            complexLim=complexLim, minLength=minLength,
+            maxLength=maxLength, splitLim=splitLim)
+
+    #Fit all species one at a time in given order from low to high wavelength
+    for species in orderFits:
+        speciesDict = speciesDicts[species]
+        speciesLines = {'N':na.array([]),
+                        'b':na.array([]),
+                        'z':na.array([]),
+                        'group#':na.array([])}
+
+        #Set up wavelengths for species
+        initWl = speciesDict['wavelength'][0]
+
+        for b_i,b in enumerate(cBounds):
+            xBounded=x[b[1]:b[2]]
+            yDatBounded=fluxData[b[1]:b[2]]
+            yFitBounded=yFit[b[1]:b[2]]
+
+            #Find init redshift
+            z=(xBounded[yDatBounded.argmin()]-initWl)/initWl
+
+            #Check if any flux at partner sites
+            if not _line_exists(speciesDict['wavelength'],
+                    fluxData,z,x0,xRes,fitLim): 
+                continue 
+
+            #Fit Using complex tools
+            newLinesP,flag=_complex_fit(xBounded,yDatBounded,yFitBounded,
+                    z,fitLim,minError*(b[2]-b[1]),speciesDict)
+
+            #Check existence of partner lines if applicable
+            newLinesP = _remove_unaccepted_partners(newLinesP, x, fluxData, 
+                    b, minError*(b[2]-b[1]),
+                    x0, xRes, speciesDict)
+
+            #If flagged as a bad fit, species is lyman alpha,
+            #   and it may be a saturated line, use special tools
+            if flag and species=='lya' and min(yDatBounded)<.1:
+                newLinesP=_large_flag_fit(xBounded,yDatBounded,
+                        yFitBounded,z,speciesDict,
+                        minSize,minError*(b[2]-b[1]))
+
+            #Adjust total current fit
+            yFit=yFit*_gen_flux_lines(x,newLinesP,speciesDict)
+
+            #Add new group to all fitted lines
+            if na.size(newLinesP)>0:
+                speciesLines['N']=na.append(speciesLines['N'],newLinesP[:,0])
+                speciesLines['b']=na.append(speciesLines['b'],newLinesP[:,1])
+                speciesLines['z']=na.append(speciesLines['z'],newLinesP[:,2])
+                groupNums = b_i*na.ones(na.size(newLinesP[:,0]))
+                speciesLines['group#']=na.append(speciesLines['group#'],groupNums)
+
+        allSpeciesLines[species]=speciesLines
+
+    if output_file:
+        _output_fit(allSpeciesLines, output_file)
+
+    return (allSpeciesLines,yFit)
+
+def _complex_fit(x, yDat, yFit, initz, minSize, errBound, speciesDict, 
+        initP=None):
+    """ Fit an absorption complex by iteratively adding and optimizing
+    voigt profiles.
+    
+    A complex is defined as a region where some number of lines may be present,
+    or a region of non zero of absorption. Lines are iteratively added
+    and optimized until the difference between the flux generated using
+    the optimized parameters has a least squares difference between the 
+    desired flux profile less than the error bound.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    initP : (,3,) ndarray
+        initial guess to try for line parameters to fit the region. Used
+        by large_flag_fit. Default = None, and initial guess generated
+        automatically.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        Array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]
+    flag : bool
+        boolean value indicating the success of the fit (True if unsuccessful)
+    """
+
+    #Setup initial line guesses
+    if initP==None: #Regular fit
+        initP = [0,0,0] 
+        if min(yDat)<.5: #Large lines get larger initial guess 
+            initP[0] = 10**16
+        elif min(yDat)>.9: #Small lines get smaller initial guess
+            initP[0] = 10**12.5
+        else:
+            initP[0] = speciesDict['init_N']
+        initP[1] = speciesDict['init_b']
+        initP[2]=initz
+        initP=na.array([initP])
+
+    linesP = initP
+
+    #For generating new z guesses
+    wl0 = speciesDict['wavelength'][0]
+
+    #Check if first line exists still
+    if min(yDat-yFit+1)>minSize: 
+        return [],False
+    
+    #Values to proceed through first run
+    errSq,prevErrSq=1,1000
+
+    while True:
+        #Initial parameter guess from joining parameters from all lines
+        #   in lines into a single array
+        initP = linesP.flatten()
+
+        #Optimize line
+        fitP,success=optimize.leastsq(_voigt_error,initP,
+                args=(x,yDat,yFit,speciesDict),
+                epsfcn=1E-10,maxfev=1000)
+
+        #Set results of optimization
+        linesP = na.reshape(fitP,(-1,3))
+
+        #Generate difference between current best fit and data
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+
+        #Sum to get idea of goodness of fit
+        errSq=sum(dif**2)
+
+        #If good enough, break
+        if errSq < errBound: 
+            break
+
+        #If last fit was worse, reject the last line and revert to last fit
+        if errSq > prevErrSq*10:
+            #If its still pretty damn bad, cut losses and try flag fit tools
+            if prevErrSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                yNewFit=_gen_flux_lines(x,prevLinesP,speciesDict)
+                break
+
+        #If too many lines 
+        if na.shape(linesP)[0]>8 or na.size(linesP)+3>=len(x):
+            #If its fitable by flag tools and still bad, use flag tools
+            if errSq >1E2*errBound and speciesDict['name']=='HI lya':
+                return [],True
+            else:
+                break 
+
+        #Store previous data in case reject next fit
+        prevErrSq = errSq
+        prevLinesP = linesP
+
+
+        #Set up initial condition for new line
+        newP = [0,0,0] 
+        if min(dif)<.1:
+            newP[0]=10**12
+        elif min(dif)>.9:
+            newP[0]=10**16
+        else:
+            newP[0]=10**14
+        newP[1] = speciesDict['init_b']
+        newP[2]=(x[dif.argmax()]-wl0)/wl0
+        linesP=na.append(linesP,[newP],axis=0)
+
+
+    #Check the parameters of all lines to see if they fall in an
+    #   acceptable range, as given in dict ref
+    remove=[]
+    for i,p in enumerate(linesP):
+        check=_check_params(na.array([p]),speciesDict)
+        if check: 
+            remove.append(i)
+    linesP = na.delete(linesP,remove,axis=0)
+
+    return linesP,False
+
+def _large_flag_fit(x, yDat, yFit, initz, speciesDict, minSize, errBound):
+    """
+    Attempts to more robustly fit saturated lyman alpha regions that have
+    not converged to satisfactory fits using the standard tools.
+
+    Uses a preselected sample of a wide range of initial parameter guesses
+    designed to fit saturated lines (see get_test_lines).
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelength
+    ydat : (N) ndarray
+        array of desired flux profile to be fitted for the wavelength
+        space given by x. Same size as x.
+    yFit : (N) ndarray
+        array of flux profile fitted for the wavelength
+        space given by x already. Same size as x.
+    initz : float
+        redshift to try putting first line at 
+        (maximum absorption for region)
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+    minsize : float
+        minimum absorption allowed for a line to still count as a line
+        given in normalized flux (ie: for minSize=.9, only lines with minimum
+        flux less than .9 will be fitted)
+    errbound : float
+        maximum total error allowed for an acceptable fit
+
+    Returns
+    -------
+    bestP : (3,) ndarray
+        array of best parameters if a good enough fit is found in 
+        the form [[N1,b1,z1], [N2,b2,z2],...]  
+    """
+
+    #Set up some initial line guesses
+    lineTests = _get_test_lines(initz)
+
+    #Keep track of the lowest achieved error
+    bestError = 1000 
+
+    #Iterate through test line guesses
+    for initLines in lineTests:
+        if initLines[1,0]==0:
+            initLines = na.delete(initLines,1,axis=0)
+
+        #Do fitting with initLines as first guess
+        linesP,flag=_complex_fit(x,yDat,yFit,initz,
+                minSize,errBound,speciesDict,initP=initLines)
+
+        #Find error of last fit
+        yNewFit=_gen_flux_lines(x,linesP,speciesDict)
+        dif = yFit*yNewFit-yDat
+        errSq=sum(dif**2)
+
+        #If error lower, keep track of the lines used to make that fit
+        if errSq < bestError:
+            bestError = errSq
+            bestP = linesP
+
+    if bestError>10*errBound*len(x): 
+        return []
+    else:
+        return bestP
+
+def _get_test_lines(initz):
+    """
+    Returns a 3d numpy array of lines to test as initial guesses for difficult
+    to fit lyman alpha absorbers that are saturated. 
+    
+    The array is 3d because
+    the first dimension gives separate initial guesses, the second dimension
+    has multiple lines for the same guess (trying a broad line plus a 
+    saturated line) and the 3d dimension contains the 3 fit parameters (N,b,z)
+
+    Parameters
+    ----------
+    initz : float
+        redshift to give all the test lines
+
+    Returns
+    -------
+    testP : (,3,) ndarray
+        numpy array of the form 
+        [[[N1a,b1a,z1a], [N1b,b1b,z1b]], [[N2a,b2,z2a],...] ...]
+    """
+
+    #Set up a bunch of empty lines
+    testP = na.zeros((10,2,3))
+
+    testP[0,0,:]=[1E18,20,initz]
+    testP[1,0,:]=[1E18,40,initz]
+    testP[2,0,:]=[1E16,5, initz]
+    testP[3,0,:]=[1E16,20,initz]
+    testP[4,0,:]=[1E16,80,initz]
+
+    testP[5,0,:]=[1E18,20,initz]
+    testP[6,0,:]=[1E18,40,initz]
+    testP[7,0,:]=[1E16,5, initz]
+    testP[8,0,:]=[1E16,20,initz]
+    testP[9,0,:]=[1E16,80,initz]
+
+    testP[5,1,:]=[1E13,100,initz]
+    testP[6,1,:]=[1E13,100,initz]
+    testP[7,1,:]=[1E13,100,initz]
+    testP[8,1,:]=[1E13,100,initz]
+    testP[9,1,:]=[1E13,100,initz]
+
+    return testP
+
+def _get_bounds(z, b, wl, x0, xRes):
+    """ 
+    Gets the indices of range of wavelength that the wavelength wl is in 
+    with the size of some initial wavelength range.
+
+    Used for checking if species with multiple lines (as in the OVI doublet)
+    fit all lines appropriately.
+
+    Parameters
+    ----------
+    z : float
+        redshift
+    b : (3) ndarray/list
+        initial bounds in form [i0,i1,i2] where i0 is the index of the 
+        minimum flux for the complex, i1 is index of the lower wavelength 
+        edge of the complex, and i2 is the index of the higher wavelength
+        edge of the complex.
+    wl : float
+        unredshifted wavelength of the peak of the new region 
+    x0 : float
+        wavelength of the index 0
+    xRes : float
+        difference in wavelength for two consecutive indices
+    
+    Returns
+    -------
+    indices : (2) tuple
+        Tuple (i1,i2) where i1 is the index of the lower wavelength bound of 
+        the new region and i2 is the index of the higher wavelength bound of
+        the new region
+    """
+
+    r=[-b[1]+100+b[0],b[2]+100-b[0]]
+    redWl = (z+1)*wl
+    iRedWl=int((redWl-x0)/xRes)
+    indices = (iRedWl-r[0],iRedWl+r[1])
+
+    return indices
+
+def _remove_unaccepted_partners(linesP, x, y, b, errBound, 
+        x0, xRes, speciesDict):
+    """
+    Given a set of parameters [N,b,z] that form multiple lines for a given
+    species (as in the OVI doublet), remove any set of parameters where
+    not all transition wavelengths have a line that matches the fit.
+
+    (ex: if a fit is determined based on the first line of the OVI doublet,
+    but the given parameters give a bad fit of the wavelength space of
+    the second line then that set of parameters is removed from the array
+    of line parameters.)
+
+    Parameters
+    ----------
+    linesP : (3,) ndarray
+        array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    x : (N) ndarray
+        wavelength array [nm]
+    y : (N) ndarray
+        normalized flux array of original data
+    b : (3) tuple/list/ndarray
+        indices that give the bounds of the original region so that another 
+        region of similar size can be used to determine the goodness
+        of fit of the other wavelengths
+    errBound : float
+        size of the error that is appropriate for a given region, 
+        adjusted to account for the size of the region.
+
+    Returns
+    -------
+    linesP : (3,) ndarray
+        array similar to linesP that only contains lines with
+        appropriate fits of all transition wavelengths.
+    """
+
+    #List of lines to remove
+    removeLines=[]
+
+    #Iterate through all sets of line parameters
+    for i,p in enumerate(linesP):
+
+        #iterate over all transition wavelengths
+        for wl in speciesDict['wavelength']:
+
+            #Get the bounds of a similar sized region around the
+            #   appropriate wavelength, and then get the appropriate
+            #   region of wavelength and flux
+            lb = _get_bounds(p[2],b,wl,x0,xRes)
+            xb,yb=x[lb[0]:lb[1]],y[lb[0]:lb[1]]
+
+            #Generate a fit and find the difference to data
+            yFitb=_gen_flux_lines(xb,na.array([p]),speciesDict)
+            dif =yb-yFitb
+
+            #Only counts as an error if line is too big ---------------<
+            dif = [k for k in dif if k>0]
+            err = sum(dif)
+
+            #If the fit is too bad then add the line to list of removed lines
+            if err > errBound*1E2:
+                removeLines.append(i)
+                break
+
+    #Remove all bad line fits
+    linesP = na.delete(linesP,removeLines,axis=0)
+
+    return linesP 
+
+
+
+def _line_exists(wavelengths, y, z, x0, xRes,fluxMin):
+    """For a group of lines finds if the there is some change in flux greater
+    than some minimum at the same redshift with different initial wavelengths
+
+    Parameters
+    ----------
+    wavelengths : (N) ndarray
+        array of initial wavelengths to check
+    y : (N) ndarray
+        flux array to check
+    x0 : float
+        wavelength of the first value in y
+    xRes : float
+        difference in wavelength between consecutive cells in flux array
+    fluxMin : float
+        maximum flux to count as a line existing. 
+
+    Returns
+    -------
+
+    flag : boolean 
+        value indicating whether all lines exist. True if all lines exist
+    """
+
+    #Iterate through initial wavelengths
+    for wl in wavelengths:
+        #Redshifted wavelength
+        redWl = (z+1)*wl
+
+        #Index of the redshifted wavelength
+        indexRedWl = (redWl-x0)/xRes
+
+        #Check if surpasses minimum absorption bound
+        if y[int(indexRedWl)]>fluxMin:
+            return False
+
+    return True
+
+def _find_complexes(x, yDat, complexLim=.999, fitLim=.99,
+        minLength =3, maxLength=1000, splitLim=.99):
+    """Breaks up the wavelength space into groups
+    where there is some absorption. 
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        array of wavelengths
+    yDat : (N) ndarray
+        array of flux corresponding to the wavelengths given
+        in x. (needs to be the same size as x)
+    complexLim : float, optional
+        Maximum flux to start the edge of an absorption complex. Different 
+        from fitLim because it decides extent of a complex rather than 
+        whether or not a complex is accepted. 
+    fitLim : float,optional
+        Maximum flux where the level of absorption will trigger 
+        identification of the region as an absorption complex. Default = .98.
+        (ex: for a minSize=.98, a region where all the flux is between 1.0 and
+        .99 will not be separated out to be fit as an absorbing complex, but
+        a region that contains a point where the flux is .97 will be fit
+        as an absorbing complex.)
+    minLength : int, optional
+        number of cells required for a complex to be included. 
+        default is 3 cells.
+    maxLength : int, optional
+        number of cells required for a complex to be split up. Default
+        is 1000 cells.
+    splitLim : float, optional
+        if attempting to split a region for being larger than maxlength
+        the point of the split must have a flux greater than splitLim 
+        (ie: absorption greater than splitLim). Default= .99.
+
+    Returns
+    -------
+    cBounds : (3,) 
+        list of bounds in the form [[i0,i1,i2],...] where i0 is the 
+        index of the maximum flux for a complex, i1 is the index of the
+        beginning of the complex, and i2 is the index of the end of the 
+        complex. Indexes refer to the indices of x and yDat.
+    """
+
+    #Initialize empty list of bounds
+    cBounds=[]
+
+    #Iterate through cells of flux
+    i=0
+    while (i<len(x)):
+
+        #Start tracking at a region that surpasses flux of edge
+        if yDat[i]<complexLim:
+
+            #Iterate through until reach next edge
+            j=0
+            while yDat[i+j]<complexLim: j=j+1
+
+            #Check if the complex is big enough
+            if j >minLength:
+
+                #Check if there is enough absorption for the complex to
+                #   be included
+                cPeak = yDat[i:i+j].argmin()
+                if yDat[cPeak+i]<fitLim:
+                    cBounds.append([cPeak+i,i,i+j])
+
+            i=i+j
+        i=i+1
+
+    i=0
+    #Iterate through the bounds
+    while i < len(cBounds):
+        b=cBounds[i]
+
+        #Check if the region needs to be divided
+        if b[2]-b[1]>maxLength:
+
+            #Find the minimum absorption in the middle two quartiles of
+            #   the large complex
+            q=(b[2]-b[1])/4
+            cut = yDat[b[1]+q:b[2]-q].argmax()+b[1]+q
+
+            #Only break it up if the minimum absorption is actually low enough
+            if yDat[cut]>splitLim:
+
+                #Get the new two peaks
+                b1Peak = yDat[b[1]:cut].argmin()+b[1]
+                b2Peak = yDat[cut:b[2]].argmin()+cut
+
+                #add the two regions separately
+                cBounds.insert(i+1,[b1Peak,b[1],cut])
+                cBounds.insert(i+2,[b2Peak,cut,b[2]])
+
+                #Remove the original region
+                cBounds.pop(i)
+                i=i+1
+        i=i+1
+
+    return cBounds
+
+def _gen_flux_lines(x, linesP, speciesDict):
+    """
+    Calculates the normalized flux for a region of wavelength space
+    generated by a set of absorption lines.
+
+    Parameters
+    ----------
+    x : (N) ndarray
+        Array of wavelength
+    linesP: (3,) ndarray
+        Array giving sets of line parameters in 
+        form [[N1, b1, z1], ...]
+    speciesDict : dictionary
+        Dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+
+    Returns
+    -------
+    flux : (N) ndarray
+        Array of normalized flux generated by the line parameters
+        given in linesP over the wavelength space given in x. Same size as x.
+    """
+    y=0
+    for p in linesP:
+        for i in range(speciesDict['numLines']):
+            f=speciesDict['f'][i]
+            g=speciesDict['Gamma'][i]
+            wl=speciesDict['wavelength'][i]
+            y = y+ _gen_tau(x,p,f,g,wl)
+    flux = na.exp(-y)
+    return flux
+
+def _gen_tau(t, p, f, Gamma, lambda_unshifted):
+    """This calculates a flux distribution for given parameters using the yt
+    voigt profile generator"""
+    N,b,z= p
+    
+    #Calculating quantities
+    tau_o = 1.4973614E-15*N*f*lambda_unshifted/b
+    a=7.95774715459E-15*Gamma*lambda_unshifted/b
+    x=299792.458/b*(lambda_unshifted*(1+z)/t-1)
+    
+    H = na.zeros(len(x))
+    H = voigt(a,x)
+    
+    tau = tau_o*H
+
+    return tau
+
+def _voigt_error(pTotal, x, yDat, yFit, speciesDict):
+    """
+    Gives the error of each point  used to optimize the fit of a group
+        of absorption lines to a given flux profile.
+
+        If the parameters are not in the acceptable range as defined
+        in speciesDict, the first value of the error array will
+        contain a large value (999), to prevent the optimizer from running
+        into negative number problems.
+
+    Parameters
+    ----------
+    pTotal : (3,) ndarray 
+        Array with form [[N1, b1, z1], ...] 
+    x : (N) ndarray
+        array of wavelengths [nm]
+    yDat : (N) ndarray
+        desired normalized flux from fits of lines in wavelength
+        space given by x
+    yFit : (N) ndarray
+        previous fit over the wavelength space given by x.
+    speciesDict : dictionary
+        dictionary containing all relevant parameters needed
+        to create an absorption line of a given species (f,Gamma,lambda0)
+        as well as max and min values for parameters to be fit
+
+    Returns
+    -------
+    error : (N) ndarray
+        the difference between the fit generated by the parameters
+        given in pTotal multiplied by the previous fit and the desired
+        flux profile, w/ first index modified appropriately for bad 
+        parameter choices
+    """
+
+    pTotal.shape = (-1,3)
+    yNewFit = _gen_flux_lines(x,pTotal,speciesDict)
+
+    error = yDat-yFit*yNewFit
+    error[0] = _check_params(pTotal,speciesDict)
+
+    return error
+
+def _check_params(p, speciesDict):
+    """
+    Check to see if any of the parameters in p fall outside the range 
+        given in speciesDict.
+
+    Parameters
+    ----------
+    p : (3,) ndarray
+        array with form [[N1, b1, z1], ...] 
+    speciesDict : dictionary
+        dictionary with properties giving the max and min
+        values appropriate for each parameter N,b, and z.
+
+    Returns
+    -------
+    check : int
+        0 if all values are fine
+        999 if any values fall outside acceptable range
+    """
+    check = 0
+    if any(p[:,0] > speciesDict['maxN']) or\
+          any(p[:,0] < speciesDict['minN']) or\
+          any(p[:,1] > speciesDict['maxb']) or\
+          any(p[:,1] < speciesDict['minb']) or\
+          any(p[:,2] > speciesDict['maxz']) or\
+          any(p[:,2] < speciesDict['minz']):
+              check = 999
+    return check
+
+
+def _output_fit(lineDic, file_name = 'spectrum_fit.h5'):
+    """
+    This function is designed to output the parameters of the series
+    of lines used to fit an absorption spectrum. 
+
+    The dataset contains entries in the form species/N, species/b
+    species/z, and species/complex. The ith entry in each of the datasets
+    is the fitted parameter for the ith line fitted to the spectrum for
+    the given species. The species names come from the fitted line
+    dictionary.
+
+    Parameters
+    ----------
+    lineDic : dictionary
+        Dictionary of dictionaries representing the fit lines. 
+        Top level keys are the species given in orderFits and the corresponding
+        entries are dictionaries with the keys 'N','b','z', and 'group#'. 
+        Each of these corresponds to a list of the parameters for every
+        accepted fitted line. 
+    fileName : string, optional
+        Name of the file to output fit to. Default = 'spectrum_fit.h5'
+
+    """
+    f = h5py.File(file_name, 'w')
+    for ion, params in lineDic.iteritems():
+        f.create_dataset("{0}/N".format(ion),data=params['N'])
+        f.create_dataset("{0}/b".format(ion),data=params['b'])
+        f.create_dataset("{0}/z".format(ion),data=params['z'])
+        f.create_dataset("{0}/complex".format(ion),data=params['group#'])
+    print 'Writing spectrum fit to {0}'.format(file_name)
+

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/analysis_modules/absorption_spectrum/api.py
--- a/yt/analysis_modules/absorption_spectrum/api.py
+++ b/yt/analysis_modules/absorption_spectrum/api.py
@@ -30,3 +30,6 @@
 
 from .absorption_spectrum import \
     AbsorptionSpectrum
+
+from .absorption_spectrum_fit import \
+    generate_total_fit

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/data_objects/setup.py
--- a/yt/data_objects/setup.py
+++ b/yt/data_objects/setup.py
@@ -8,7 +8,7 @@
 def configuration(parent_package='', top_path=None):
     from numpy.distutils.misc_util import Configuration
     config = Configuration('data_objects', parent_package, top_path)
+    config.add_subpackage("tests")
     config.make_config_py()  # installs __config__.py
-    config.add_subpackage("tests")
     #config.make_svn_version_py()
     return config

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -70,6 +70,8 @@
             obj = object.__new__(cls)
             if obj._skip_cache is False:
                 _cached_pfs[apath] = obj
+        else:
+            obj = _cached_pfs[apath]
         return obj
 
     def __init__(self, filename, data_style=None, file_style=None):

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/frontends/athena/data_structures.py
--- a/yt/frontends/athena/data_structures.py
+++ b/yt/frontends/athena/data_structures.py
@@ -91,12 +91,11 @@
     splitup = line.strip().split()
     if "vtk" in splitup:
         grid['vtk_version'] = splitup[-1]
-    elif "Really" in splitup:
-        grid['time'] = splitup[-1]
-    elif any(x in ['PRIMITIVE','CONSERVED'] for x in splitup):
-        grid['time'] = float(splitup[4].rstrip(','))
-        grid['level'] = int(splitup[6].rstrip(','))
-        grid['domain'] = int(splitup[8].rstrip(','))
+    elif "time=" in splitup:
+        time_index = splitup.index("time=")
+        grid['time'] = float(splitup[time_index+1].rstrip(','))
+        grid['level'] = int(splitup[time_index+3].rstrip(','))
+        grid['domain'] = int(splitup[time_index+5].rstrip(','))                        
     elif "DIMENSIONS" in splitup:
         grid['dimensions'] = np.array(splitup[-3:]).astype('int')
     elif "ORIGIN" in splitup:

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/funcs.py
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -250,6 +250,17 @@
      %(filename)s:%(lineno)s
 """
 
+def get_ipython_api_version():
+    import IPython
+    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
+        api_version = '0.10'
+    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
+        api_version = '0.11'
+    else:
+        api_version = '1.0'
+
+    return api_version
+
 def insert_ipython(num_up=1):
     """
     Placed inside a function, this will insert an IPython interpreter at that
@@ -259,13 +270,7 @@
     defaults to 1 so that this function itself is stripped off.
     """
 
-    import IPython
-    if LooseVersion(IPython.__version__) <= LooseVersion('0.10'):
-        api_version = '0.10'
-    elif LooseVersion(IPython.__version__) <= LooseVersion('1.0'):
-        api_version = '0.11'
-    else:
-        api_version = '1.0'
+    api_version = get_ipython_api_version()
 
     stack = inspect.stack()
     frame = inspect.stack()[num_up]

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/startup_tasks.py
--- a/yt/startup_tasks.py
+++ b/yt/startup_tasks.py
@@ -36,9 +36,11 @@
 def turn_on_parallelism():
     try:
         from mpi4py import MPI
-        parallel_capable = (MPI.COMM_WORLD.size > 1)
-    except ImportError:
-        parallel_capable = False
+    except ImportError as e:
+        mylog.error("Warning: Attempting to turn on parallelism, " +
+                    "but mpi4py import failed. Try pip install mpi4py.")
+        raise e
+    parallel_capable = (MPI.COMM_WORLD.size > 1)
     if parallel_capable:
         mylog.info("Global parallel computation enabled: %s / %s",
                    MPI.COMM_WORLD.rank, MPI.COMM_WORLD.size)

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -270,7 +270,7 @@
     with temp_cwd(path):
         try:
             load(pf_fn)
-        except:
+        except YTOutputNotIdentified:
             return False
     return AnswerTestingTest.result_storage is not None
 

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/utilities/lib/grid_traversal.pyx
--- a/yt/utilities/lib/grid_traversal.pyx
+++ b/yt/utilities/lib/grid_traversal.pyx
@@ -67,7 +67,7 @@
     np.float64_t idds[3]
     int dims[3]
 
-ctypedef void sample_function(
+ctypedef void sampler_function(
                 VolumeContainer *vc,
                 np.float64_t v_pos[3],
                 np.float64_t v_dir[3],
@@ -235,7 +235,7 @@
 
 cdef class ImageSampler:
     cdef ImageContainer *image
-    cdef sample_function *sampler
+    cdef sampler_function *sampler
     cdef public object avp_pos, avp_dir, acenter, aimage, ax_vec, ay_vec
     cdef void *supp_data
     cdef np.float64_t width[3]
@@ -929,7 +929,7 @@
 cdef int walk_volume(VolumeContainer *vc,
                      np.float64_t v_pos[3],
                      np.float64_t v_dir[3],
-                     sample_function *sampler,
+                     sampler_function *sampler,
                      void *data,
                      np.float64_t *return_t = NULL,
                      np.float64_t enter_t = -1.0) nogil:

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -23,6 +23,7 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 import matplotlib
+import cStringIO
 from ._mpl_imports import \
     FigureCanvasAgg, FigureCanvasPdf, FigureCanvasPS
 from yt.funcs import \
@@ -96,3 +97,10 @@
                                       norm=norm, vmin=self.zmin, aspect=aspect,
                                       vmax=self.zmax, cmap=cmap)
         self.cb = self.figure.colorbar(self.image, self.cax)
+
+    def _repr_png_(self):
+        canvas = FigureCanvasAgg(self.figure)
+        f = cStringIO.StringIO()
+        canvas.print_figure(f)
+        f.seek(0)
+        return f.read()

diff -r cfbecf7f8933b3d3b82b8b2fe5e143cb0b24901e -r b17c65836c1df8829d4d06709c24bc4a4f517ecc yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -52,7 +52,7 @@
 from yt.utilities.delaunay.triangulate import Triangulation as triang
 from yt.funcs import \
     mylog, defaultdict, iterable, ensure_list, \
-    fix_axis, get_image_suffix
+    fix_axis, get_image_suffix, get_ipython_api_version
 from yt.utilities.lib import write_png_to_string
 from yt.utilities.definitions import \
     x_dict, y_dict, \
@@ -1123,7 +1123,11 @@
 
         """
         if "__IPYTHON__" in dir(__builtin__):
-            self._send_zmq()
+            api_version = get_ipython_api_version()
+            if api_version in ('0.10', '0.11'):
+                self._send_zmq()
+            else:
+                return self
         else:
             raise YTNotInsideNotebook
 
@@ -1135,10 +1139,14 @@
         except YTNotInsideNotebook:
             return self.save(name=name, mpl_kwargs=mpl_kwargs)
 
-    def __repr__(self):
-        if "__IPYTHON__" in dir(__builtin__):
-            self.show()
-        return super(PWViewerMPL, self).__repr__()
+    def _repr_html_(self):
+        """Return an html representation of the plot object. Will display as a
+        png for each WindowPlotMPL instance in self.plots"""
+        ret = ''
+        for field in self.plots:
+            img = base64.b64encode(self.plots[field]._repr_png_())
+            ret += '<img src="data:image/png;base64,%s"><br>' % img
+        return ret
 
 class SlicePlot(PWViewerMPL):
     r"""Creates a slice plot from a parameter file


https://bitbucket.org/yt_analysis/yt-3.0/commits/f633de3b779a/
Changeset:   f633de3b779a
Branch:      yt
User:        chummels
Date:        2013-08-15 03:14:05
Summary:     Updating docstrings of halo_objects for merger.
Affected #:  1 file

diff -r b17c65836c1df8829d4d06709c24bc4a4f517ecc -r f633de3b779a7c4c44cbc89a41e2841e076c2b46 yt/analysis_modules/halo_finding/halo_objects.py
--- a/yt/analysis_modules/halo_finding/halo_objects.py
+++ b/yt/analysis_modules/halo_finding/halo_objects.py
@@ -1061,8 +1061,9 @@
     def __init__(self, data_source, dm_only=True, redshift=-1):
         """
         Run hop on *data_source* with a given density *threshold*.  If
-        *dm_only* is True (default), only run it on the dark matter particles, otherwise
-        on all particles.  Returns an iterable collection of *HopGroup* items.
+        *dm_only* is True (default), only run it on the dark matter particles, 
+        otherwise on all particles.  Returns an iterable collection of 
+        *HopGroup* items.
         """
         self._data_source = data_source
         self.dm_only = dm_only


https://bitbucket.org/yt_analysis/yt-3.0/commits/04d5ff482af3/
Changeset:   04d5ff482af3
Branch:      yt
User:        chummels
Date:        2013-08-16 01:18:06
Summary:     Updating annotate_grids() callback to use the same coloring mechanism for each level as is used by the camera.add_grids() function (in volume renderings).  Updating docstrings.
Affected #:  1 file

diff -r f633de3b779a7c4c44cbc89a41e2841e076c2b46 -r 04d5ff482af32caccc96ebeb6b6bd12e0f991f2e yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -44,6 +44,7 @@
     sec_per_Gyr, sec_per_Myr, \
     sec_per_kyr, sec_per_year, \
     sec_per_day, sec_per_hr
+from yt.visualization.image_writer import apply_colormap
 
 import _MPL
 
@@ -337,29 +338,49 @@
 
 class GridBoundaryCallback(PlotCallback):
     """
-    annotate_grids(alpha=1.0, min_pix=1, min_pix_ids=20, draw_ids=False, 
-                   periodic=True, min_level=None, max_level=None, 
-                   shaded_levels=False)
+    annotate_grids()
 
-    Overplots grid boundaries on a plot, optionally with *alpha*-blending.
-    Cutoff for display is at *min_pix* width.  
+    Draws grids on an existing PlotWindow object.
 
-    *draw_ids* puts the grid id in the corner of each grid.  
-    (Not so great in projections...)
+    Parameters
+    ----------
+    alpha: float, optional
+        The alpha value for the grids being drawn.  Used to control
+        how bright the grid lines are with respect to the image.
+        Default : 0.3
 
-    Grids must be wider than *min_pix_ids* otherwise the ID will not be drawn.  
+    cmap : string, optional
+        Colormap to be used mapping grid levels to colors.  If 
+        cmap is set to None, will default to all black grid boxes.
+        Default : 'algae'
+
+    min_pix : int, optional
+        If a grid patch is smaller than min_pix pixels in size in image
+        space, it will not be displayed.
+        Default : 1
     
-    If *min_level* is specified, only draw grids at or above min_level.  
-    
-    If *max_level* is specified, only draw grids at or below max_level.
+    min_pix_ids : int, optional
+        If a grid patch is smaller than min_pix_ids pixels in size in 
+        image space, it will not be labeled with an id (only applies
+        when using the *draw_ids* kwarg).
+        Default : 20
 
-    If *shaded_levels* is True, then differentiate between different levels
-    of refinement with different shades of white/gray/black, with white
-    as the lowest level and black as the highest level of refinement.
+    draw_ids : bool, optional
+        When set, labels each grid with ID number.
+        Default : False
+
+    periodic : bool, optional
+        Retains periodic behavior of grids at volume boundaries.
+        Default : False
+
+    min_level, max_level : int, optional
+        Optional parameters to specify the min and max level grid boxes
+        to overplot on the image.
+
     """
     _type_name = "grids"
-    def __init__(self, alpha=1.0, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
-                 min_level=None, max_level=None, shaded_levels=False):
+    def __init__(self, alpha=0.3, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
+                 min_level=None, max_level=None, cmap='algae'):
         PlotCallback.__init__(self)
         self.alpha = alpha
         self.min_pix = min_pix
@@ -368,7 +389,7 @@
         self.periodic = periodic
         self.min_level = min_level
         self.max_level = max_level
-        self.shaded_levels = shaded_levels
+        self.cmap = cmap
 
     def __call__(self, plot):
         x0, x1 = plot.xlim
@@ -407,38 +428,28 @@
                        ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix ) & \
                        ( grid_levels >= min_level) & \
                        ( grid_levels <= max_level)
+            if self.cmap is not None: 
+                edgecolors = apply_colormap(grid_levels*1.0,
+                                  color_bounds=[0,plot.data.pf.h.max_level],
+                                  cmap_name=self.cmap)[0,:,:]*1.0/255.
+            else:
+                edgecolors = (0.0,0.0,0.0,self.alpha)
+            edgecolors[:,3] = self.alpha
+
             if visible.nonzero()[0].size == 0: continue
             verts = np.array(
                 [(left_edge_x, left_edge_x, right_edge_x, right_edge_x),
                  (left_edge_y, right_edge_y, right_edge_y, left_edge_y)])
-            if not self.shaded_levels:
-                verts=verts.transpose()[visible,:,:]
-                edgecolors = (0.0,0.0,0.0,self.alpha)
-                grid_collection = matplotlib.collections.PolyCollection(
-                    verts, facecolors="none",
-                    edgecolors=edgecolors)
-                plot._axes.hold(True)
-                plot._axes.add_collection(grid_collection)
-            # if shaded_levels is defined, then make the different
-            # grid boxes different colors.  lowest level of resolution
-            # is white and go up in shades of gray to highest level
-            # of resolution which is black.
-            else:
-                level_range = max_level - min_level
-                for j,level in enumerate(range(min_level, max_level+1)):
-                    edge_shade = 1-(j*(1./level_range))
-                    edgecolors = (edge_shade, edge_shade, edge_shade, self.alpha)
-                    one_level =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix ) & \
-                                 ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix ) & \
-                                 ( grid_levels == level)
-                    grid_collection = matplotlib.collections.PolyCollection(
-                                      verts.transpose()[one_level,:,:], facecolors="none",
-                                      edgecolors=edgecolors)
-                    plot._axes.hold(True)
-                    plot._axes.add_collection(grid_collection)
+            verts=verts.transpose()[visible,:,:]
+            grid_collection = matplotlib.collections.PolyCollection(
+                verts, facecolors="none",
+                edgecolors=edgecolors)
+            plot._axes.hold(True)
+            plot._axes.add_collection(grid_collection)
+
             if self.draw_ids:
                 visible_ids =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix_ids ) & \
-                               ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix_ids ) 
+                               ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix_ids )
                 active_ids = np.unique(plot.data['GridIndices'])
                 for i in np.where(visible_ids)[0]:
                     plot._axes.text(


https://bitbucket.org/yt_analysis/yt-3.0/commits/3e1184e4d8e6/
Changeset:   3e1184e4d8e6
Branch:      yt
User:        chummels
Date:        2013-08-16 01:18:21
Summary:     Fixing typo in docstrings.
Affected #:  1 file

diff -r 04d5ff482af32caccc96ebeb6b6bd12e0f991f2e -r 3e1184e4d8e6d9cd08a1f7832914063e58551927 yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -277,7 +277,7 @@
                    max_level=None):
         r"""Draws Grids on an existing volume rendering.
 
-        By mapping grid level to a color, drawes edges of grids on 
+        By mapping grid level to a color, draws edges of grids on 
         a volume rendering using the camera orientation.
 
         Parameters


https://bitbucket.org/yt_analysis/yt-3.0/commits/6ead0f903648/
Changeset:   6ead0f903648
Branch:      yt
User:        chummels
Date:        2013-08-16 03:02:39
Summary:     Adding in the "reversals" of all of the colormaps contained in the _colormap_data.py file.  Each reversed colormap is denoted "<cmap>_r" consistent with the MPL convention.
Affected #:  1 file

diff -r 3e1184e4d8e6d9cd08a1f7832914063e58551927 -r 6ead0f903648ea7d6af548eb0166b8c135f5ba36 yt/visualization/_colormap_data.py
--- a/yt/visualization/_colormap_data.py
+++ b/yt/visualization/_colormap_data.py
@@ -7798,3 +7798,11 @@
 color_map_luts['Rainbow18'] = color_map_luts['idl38']
 color_map_luts['Rainbow + white'] = color_map_luts['idl39']
 color_map_luts['Rainbow + black'] = color_map_luts['idl40']
+
+# Create a reversed LUT for each of the above defined LUTs
+# and append a "_r" (for reversal. consistent with MPL convention).
+# So for example, the reversal of "Waves" is "Waves_r"
+temp = {}
+for k,v in color_map_luts.iteritems():
+    temp[k+"_r"] = (v[0][::-1], v[1][::-1], v[2][::-1], v[3][::-1])
+color_map_luts.update(temp)


https://bitbucket.org/yt_analysis/yt-3.0/commits/17e26777b58a/
Changeset:   17e26777b58a
Branch:      yt
User:        chummels
Date:        2013-08-16 03:27:19
Summary:     Choosing better defaults for the annotate_grids callback.
Affected #:  1 file

diff -r 6ead0f903648ea7d6af548eb0166b8c135f5ba36 -r 17e26777b58adbd3dfb379d11339fd9f5308357d yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -379,8 +379,8 @@
 
     """
     _type_name = "grids"
-    def __init__(self, alpha=0.3, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
-                 min_level=None, max_level=None, cmap='algae'):
+    def __init__(self, alpha=0.7, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
+                 min_level=None, max_level=None, cmap='B-W LINEAR_r'):
         PlotCallback.__init__(self)
         self.alpha = alpha
         self.min_pix = min_pix


https://bitbucket.org/yt_analysis/yt-3.0/commits/4442c8f389ca/
Changeset:   4442c8f389ca
Branch:      yt
User:        chummels
Date:        2013-08-16 03:34:08
Summary:     Fixing a bug.
Affected #:  1 file

diff -r 17e26777b58adbd3dfb379d11339fd9f5308357d -r 4442c8f389ca4420a495152f204917192fb64073 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -432,9 +432,9 @@
                 edgecolors = apply_colormap(grid_levels*1.0,
                                   color_bounds=[0,plot.data.pf.h.max_level],
                                   cmap_name=self.cmap)[0,:,:]*1.0/255.
+                edgecolors[:,3] = self.alpha
             else:
                 edgecolors = (0.0,0.0,0.0,self.alpha)
-            edgecolors[:,3] = self.alpha
 
             if visible.nonzero()[0].size == 0: continue
             verts = np.array(


https://bitbucket.org/yt_analysis/yt-3.0/commits/29103f56f2bd/
Changeset:   29103f56f2bd
Branch:      yt
User:        chummels
Date:        2013-08-16 03:54:16
Summary:     Fixing up the levels to be simpler and more consistent.
Affected #:  1 file

diff -r 4442c8f389ca4420a495152f204917192fb64073 -r 29103f56f2bdff37eb4d0bb438688d285b2e4650 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -409,13 +409,15 @@
             pxs, pys = np.mgrid[0:0:1j,0:0:1j]
         GLE = plot.data.grid_left_edge
         GRE = plot.data.grid_right_edge
-        grid_levels = plot.data.grid_levels[:,0]
+        levels = plot.data.grid_levels[:,0]
         min_level = self.min_level
         max_level = self.max_level
-        if min_level is None:
-            min_level = 0
-        if max_level is None:
-            max_level = plot.data.pf.h.max_level
+        if max_level is not None:
+            subset = levels <= max_level
+            levels = levels[subset]
+        if min_level is not None:
+            subset = levels >= min_level
+            levels = levels[subset]
 
         for px_off, py_off in zip(pxs.ravel(), pys.ravel()):
             pxo = px_off * dom[px_index]
@@ -425,11 +427,9 @@
             right_edge_x = (GRE[:,px_index]+pxo-x0)*dx + xx0
             right_edge_y = (GRE[:,py_index]+pyo-y0)*dy + yy0
             visible =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix ) & \
-                       ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix ) & \
-                       ( grid_levels >= min_level) & \
-                       ( grid_levels <= max_level)
+                       ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix )
             if self.cmap is not None: 
-                edgecolors = apply_colormap(grid_levels*1.0,
+                edgecolors = apply_colormap(levels*1.0,
                                   color_bounds=[0,plot.data.pf.h.max_level],
                                   cmap_name=self.cmap)[0,:,:]*1.0/255.
                 edgecolors[:,3] = self.alpha


https://bitbucket.org/yt_analysis/yt-3.0/commits/fe9d82f90772/
Changeset:   fe9d82f90772
Branch:      yt
User:        chummels
Date:        2013-08-16 05:06:14
Summary:     Fixing a bug whereby if min_level and max_level weren't defined, the annotate_grids function failed.  Also simplified the code a bit.
Affected #:  1 file

diff -r 29103f56f2bdff37eb4d0bb438688d285b2e4650 -r fe9d82f907720599b0e46edba24b0cac06b62c5c yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -347,12 +347,14 @@
     alpha: float, optional
         The alpha value for the grids being drawn.  Used to control
         how bright the grid lines are with respect to the image.
-        Default : 0.3
+        Default : 0.7
 
     cmap : string, optional
         Colormap to be used mapping grid levels to colors.  If 
         cmap is set to None, will default to all black grid boxes.
-        Default : 'algae'
+        The default colormap was chosen to give shades of white to black
+        as the refinement level increases.
+        Default : 'B-W LINEAR_r'
 
     min_pix : int, optional
         If a grid patch is smaller than min_pix pixels in size in image
@@ -412,12 +414,10 @@
         levels = plot.data.grid_levels[:,0]
         min_level = self.min_level
         max_level = self.max_level
-        if max_level is not None:
-            subset = levels <= max_level
-            levels = levels[subset]
-        if min_level is not None:
-            subset = levels >= min_level
-            levels = levels[subset]
+        if max_level is None:
+            max_level = plot.data.pf.h.max_level
+        if min_level is None:
+            min_level = 0
 
         for px_off, py_off in zip(pxs.ravel(), pys.ravel()):
             pxo = px_off * dom[px_index]
@@ -427,9 +427,12 @@
             right_edge_x = (GRE[:,px_index]+pxo-x0)*dx + xx0
             right_edge_y = (GRE[:,py_index]+pyo-y0)*dy + yy0
             visible =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix ) & \
-                       ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix )
+                       ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix ) & \
+                       ( levels >= min_level) & \
+                       ( levels <= max_level)
+
             if self.cmap is not None: 
-                edgecolors = apply_colormap(levels*1.0,
+                edgecolors = apply_colormap(levels[(levels <= max_level) & (levels >= min_level)]*1.0,
                                   color_bounds=[0,plot.data.pf.h.max_level],
                                   cmap_name=self.cmap)[0,:,:]*1.0/255.
                 edgecolors[:,3] = self.alpha


https://bitbucket.org/yt_analysis/yt-3.0/commits/ff6095a3185a/
Changeset:   ff6095a3185a
Branch:      yt
User:        chummels
Date:        2013-08-16 05:06:55
Summary:     Merging.
Affected #:  1 file

diff -r fe9d82f907720599b0e46edba24b0cac06b62c5c -r ff6095a3185a9fba22fe5a1f33e3e41d357d8b7e yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1127,7 +1127,8 @@
             if api_version in ('0.10', '0.11'):
                 self._send_zmq()
             else:
-                return self
+                from IPython.display import display
+                display(self)
         else:
             raise YTNotInsideNotebook
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/8ddc4dd0d42e/
Changeset:   8ddc4dd0d42e
Branch:      yt
User:        chummels
Date:        2013-08-16 23:05:58
Summary:     Updating docstrings to match actual callbacks in plot_modification.py
Affected #:  1 file

diff -r ff6095a3185a9fba22fe5a1f33e3e41d357d8b7e -r 8ddc4dd0d42e7b6fcbbcc8f9be7e9dae627bf970 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -176,7 +176,8 @@
 
 class QuiverCallback(PlotCallback):
     """
-    annotate_quiver(field_x, field_y, factor, scale=None, scale_units=None, normalize=False):
+    annotate_quiver(field_x, field_y, factor=16, scale=None, scale_units=None, 
+                    normalize=False, bv_x=0, bv_y=0):
 
     Adds a 'quiver' plot to any plot, using the *field_x* and *field_y*
     from the associated data, skipping every *factor* datapoints
@@ -230,8 +231,8 @@
 
 class ContourCallback(PlotCallback):
     """
-    annotate_contour(self, field, ncont=5, factor=4, take_log=None, clim=None,
-                     plot_args = None):
+    annotate_contour(field, ncont=5, factor=4, take_log=None, clim=None,
+                     plot_args=None, label=False, label_args=None):
 
     Add contours in *field* to the plot.  *ncont* governs the number of
     contours generated, *factor* governs the number of points used in the
@@ -338,7 +339,8 @@
 
 class GridBoundaryCallback(PlotCallback):
     """
-    annotate_grids()
+    annotate_grids(alpha=0.7, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
+                 min_level=None, max_level=None, cmap='B-W LINEAR_r'):
 
     Draws grids on an existing PlotWindow object.
 


https://bitbucket.org/yt_analysis/yt-3.0/commits/a820a4081ce8/
Changeset:   a820a4081ce8
Branch:      yt
User:        chummels
Date:        2013-08-16 23:06:16
Summary:     Merging.
Affected #:  3 files

diff -r 8ddc4dd0d42e7b6fcbbcc8f9be7e9dae627bf970 -r a820a4081ce82cd759d13fc46c216bae3066cbc5 doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -473,11 +473,18 @@
 function do_setup_py
 {
     [ -e $1/done ] && return
-    echo "Installing $1 (arguments: '$*')"
-    [ ! -e $1/extracted ] && tar xfz $1.tar.gz
-    touch $1/extracted
-    cd $1
-    if [ ! -z `echo $1 | grep h5py` ]
+    LIB=$1
+    shift
+    if [ -z "$@" ]
+    then
+        echo "Installing $LIB"
+    else
+        echo "Installing $LIB (arguments: '$@')"
+    fi
+    [ ! -e $LIB/extracted ] && tar xfz $LIB.tar.gz
+    touch $LIB/extracted
+    cd $LIB
+    if [ ! -z `echo $LIB | grep h5py` ]
     then
         shift
 	( ${DEST_DIR}/bin/python2.7 setup.py build --hdf5=${HDF5_DIR} $* 2>&1 ) 1>> ${LOG_FILE} || do_exit
@@ -519,8 +526,8 @@
 
 function get_ytproject
 {
+    [ -e $1 ] && return
     echo "Downloading $1 from yt-project.org"
-    [ -e $1 ] && return
     ${GETFILE} "http://yt-project.org/dependencies/$1" || do_exit
     ( ${SHASUM} -c $1.sha512 2>&1 ) 1>> ${LOG_FILE} || do_exit
 }
@@ -551,67 +558,93 @@
 mkdir -p ${DEST_DIR}/src
 cd ${DEST_DIR}/src
 
+CYTHON='Cython-0.19.1'
+FORTHON='Forthon-0.8.11'
+PYX='PyX-0.12.1'
+PYTHON='Python-2.7.5'
+BZLIB='bzip2-1.0.6'
+FREETYPE_VER='freetype-2.4.12'
+H5PY='h5py-2.1.3'
+HDF5='hdf5-1.8.11'
+IPYTHON='ipython-1.0.0'
+LAPACK='lapack-3.4.2'
+PNG=libpng-1.6.3
+MATPLOTLIB='matplotlib-1.3.0'
+MERCURIAL='mercurial-2.7'
+NOSE='nose-1.3.0'
+NUMPY='numpy-1.7.1'
+PYTHON_HGLIB='python-hglib-1.0'
+PYZMQ='pyzmq-13.1.0'
+ROCKSTAR='rockstar-0.99.6'
+SCIPY='scipy-0.12.0'
+SQLITE='sqlite-autoconf-3071700'
+SYMPY='sympy-0.7.3'
+TORNADO='tornado-3.1'
+ZEROMQ='zeromq-3.2.3'
+ZLIB='zlib-1.2.8'
+
 # Now we dump all our SHA512 files out.
-echo 'fb85d71bb4f80b35f0d0f1735c650dd75c5f84b05635ddf91d6241ff103b5a49158c5b851a20c15e05425f6dde32a4971b35fcbd7445f61865b4d61ffd1fbfa1  Cython-0.18.tar.gz' > Cython-0.18.tar.gz.sha512
+echo '9dcdda5b2ee2e63c2d3755245b7b4ed2f4592455f40feb6f8e86503195d9474559094ed27e789ab1c086d09da0bb21c4fe844af0e32a7d47c81ff59979b18ca0  Cython-0.19.1.tar.gz' > Cython-0.19.1.tar.gz.sha512
+echo '3f53d0b474bfd79fea2536d0a9197eaef6c0927e95f2f9fd52dbd6c1d46409d0e649c21ac418d8f7767a9f10fe6114b516e06f2be4b06aec3ab5bdebc8768220  Forthon-0.8.11.tar.gz' > Forthon-0.8.11.tar.gz.sha512
 echo '4941f5aa21aff3743546495fb073c10d2657ff42b2aff401903498638093d0e31e344cce778980f28a7170c6d29eab72ac074277b9d4088376e8692dc71e55c1  PyX-0.12.1.tar.gz' > PyX-0.12.1.tar.gz.sha512
-echo '3349152c47ed2b63c5c9aabcfa92b8497ea9d71ca551fd721e827fcb8f91ff9fbbee6bba8f8cb2dea185701b8798878b4b2435c1496b63d4b4a37c624a625299  Python-2.7.4.tgz' > Python-2.7.4.tgz.sha512
+echo 'd6580eb170b36ad50f3a30023fe6ca60234156af91ccb3971b0b0983119b86f3a9f6c717a515c3c6cb72b3dcbf1d02695c6d0b92745f460b46a3defd3ff6ef2f  Python-2.7.5.tgz' > Python-2.7.5.tgz.sha512
+echo '172f2bc671145ebb0add2669c117863db35851fb3bdb192006cd710d4d038e0037497eb39a6d01091cb923f71a7e8982a77b6e80bf71d6275d5d83a363c8d7e5  rockstar-0.99.6.tar.gz' > rockstar-0.99.6.tar.gz.sha512
+echo '276bd9c061ec9a27d478b33078a86f93164ee2da72210e12e2c9da71dcffeb64767e4460b93f257302b09328eda8655e93c4b9ae85e74472869afbeae35ca71e  blas.tar.gz' > blas.tar.gz.sha512
 echo '00ace5438cfa0c577e5f578d8a808613187eff5217c35164ffe044fbafdfec9e98f4192c02a7d67e01e5a5ccced630583ad1003c37697219b0f147343a3fdd12  bzip2-1.0.6.tar.gz' > bzip2-1.0.6.tar.gz.sha512
 echo 'a296dfcaef7e853e58eed4e24b37c4fa29cfc6ac688def048480f4bb384b9e37ca447faf96eec7b378fd764ba291713f03ac464581d62275e28eb2ec99110ab6  reason-js-20120623.zip' > reason-js-20120623.zip.sha512
-echo 'b46c93d76f8ce09c94765b20b2eeadf71207671f1131777de178b3727c235b4dd77f6e60d62442b96648c3c6749e9e4c1194c1b02af7e946576be09e1ff7ada3  freetype-2.4.11.tar.gz' > freetype-2.4.11.tar.gz.sha512
-echo '15ca0209e8d8f172cb0708a2de946fbbde8551d9bebc4a95fa7ae31558457a7f43249d5289d7675490c577deb4e0153698fd2407644078bf30bd5ab10135fce3  h5py-2.1.2.tar.gz' > h5py-2.1.2.tar.gz.sha512
-echo 'c68a425bacaa7441037910b9166f25b89e1387776a7749a5350793f89b1690350df5f018060c31d03686e7c3ed2aa848bd2b945c96350dc3b6322e087934783a  hdf5-1.8.9.tar.gz' > hdf5-1.8.9.tar.gz.sha512
-echo 'b2b53ed358bacab9e8d63a51f17bd5f121ece60a1d7c53e8a8eb08ad8b1e4393a8d7a86eec06e2efc62348114f0d84c0a3dfc805e68e6edd93b20401962b3554  libpng-1.6.1.tar.gz' > libpng-1.6.1.tar.gz.sha512
-echo '497f91725eaf361bdb9bdf38db2bff5068a77038f1536df193db64c9b887e3b0d967486daee722eda6e2c4e60f034eee030673e53d07bf0db0f3f7c0ef3bd208  matplotlib-1.2.1.tar.gz' > matplotlib-1.2.1.tar.gz.sha512
-echo '928fdeaaf0eaec80adbd8765521de9666ab56aaa2101fb9ab2cb392d8b29475d3b052d89652ff9b67522cfcc6cd958717ac715f51b0573ee088e9a595f29afe2  mercurial-2.5.4.tar.gz' > mercurial-2.5.4.tar.gz.sha512
-echo 'a485daa556f6c76003de1dbb3e42b3daeee0a320c69c81b31a7d2ebbc2cf8ab8e96c214a4758e5e7bf814295dc1d6aa563092b714db7e719678d8462135861a8  numpy-1.7.0.tar.gz' > numpy-1.7.0.tar.gz.sha512
-echo '293d78d14a9347cb83e1a644e5f3e4447ed6fc21642c51683e5495dda08d2312194a73d1fc3c1d78287e33ed065aa251ecbaa7c0ea9189456c1702e96d78becd  sqlite-autoconf-3071601.tar.gz' > sqlite-autoconf-3071601.tar.gz.sha512
-echo 'b1c073ad26684e354f7c522c14655840592e03872bc0a94690f89cae2ff88f146fce1dad252ff27a889dac4a32ff9f8ab63ba940671f9da89e9ba3e19f1bf58d  zlib-1.2.7.tar.gz' > zlib-1.2.7.tar.gz.sha512
-echo '05ac335727a2c3036f31a2506fdd2615aa436bfbe2f81799fe6c51bffe2591ad6a8427f3b25c34e7e709fb4e7607a0589dc7a22185c1f9b894e90de6711a88aa  ipython-0.13.1.tar.gz' > ipython-0.13.1.tar.gz.sha512
-echo 'b9d061ca49e54ea917e0aed2b2a48faef33061dbf6d17eae7f8c3fff0b35ca883e7324f6cb24bda542443f669dcd5748037a5f2309f4c359d68adef520894865  zeromq-3.2.2.tar.gz' > zeromq-3.2.2.tar.gz.sha512
-echo '852fce8a8308c4e1e4b19c77add2b2055ca2ba570b28e8364888df490af92b860c72e860adfb075b3405a9ceb62f343889f20a8711c9353a7d9059adee910f83  pyzmq-13.0.2.tar.gz' > pyzmq-13.0.2.tar.gz.sha512
-echo '303bd3fbea22be57fddf7df78ddf5a783d355a0c8071b1363250daafc20232ddd28eedc44aa1194f4a7afd82f9396628c5bb06819e02b065b6a1b1ae8a7c19e1  tornado-3.0.tar.gz' > tornado-3.0.tar.gz.sha512
-echo '3f53d0b474bfd79fea2536d0a9197eaef6c0927e95f2f9fd52dbd6c1d46409d0e649c21ac418d8f7767a9f10fe6114b516e06f2be4b06aec3ab5bdebc8768220  Forthon-0.8.11.tar.gz' > Forthon-0.8.11.tar.gz.sha512
-echo 'c13116c1f0547000cc565e15774687b9e884f8b74fb62a84e578408a868a84961704839065ae4f21b662e87f2aaedf6ea424ea58dfa9d3d73c06281f806d15dd  nose-1.2.1.tar.gz' > nose-1.2.1.tar.gz.sha512
-echo 'd67de9567256e6f1649e4f3f7dfee63371d5f00fd3fd4f92426198f862e97c57f70e827d19f4e5e1929ad85ef2ce7aa5a0596b101cafdac71672e97dc115b397  python-hglib-0.3.tar.gz' > python-hglib-0.3.tar.gz.sha512
-echo 'ffc602eb346717286b3d0a6770c60b03b578b3cf70ebd12f9e8b1c8c39cdb12ef219ddaa041d7929351a6b02dbb8caf1821b5452d95aae95034cbf4bc9904a7a  sympy-0.7.2.tar.gz' > sympy-0.7.2.tar.gz.sha512
+echo '609a68a3675087e0cc95268574f31e104549daa48efe15a25a33b8e269a93b4bd160f4c3e8178dca9c950ef5ca514b039d6fd1b45db6af57f25342464d0429ce  freetype-2.4.12.tar.gz' > freetype-2.4.12.tar.gz.sha512
+echo '2eb7030f8559ff5cb06333223d98fda5b3a663b6f4a026949d1c423aa9a869d824e612ed5e1851f3bf830d645eea1a768414f73731c23ab4d406da26014fe202  h5py-2.1.3.tar.gz' > h5py-2.1.3.tar.gz.sha512
+echo 'e9db26baa297c8ed10f1ca4a3fcb12d6985c6542e34c18d48b2022db73014f054c8b8434f3df70dcf44631f38b016e8050701d52744953d0fced3272d7b6b3c1  hdf5-1.8.11.tar.gz' > hdf5-1.8.11.tar.gz.sha512
+echo '1b309c08009583e66d1725a2d2051e6de934db246129568fa6d5ba33ad6babd3b443e7c2782d817128d2b112e21bcdd71e66be34fbd528badd900f1d0ed3db56  ipython-1.0.0.tar.gz' > ipython-1.0.0.tar.gz.sha512
+echo '8770214491e31f0a7a3efaade90eee7b0eb20a8a6ab635c5f854d78263f59a1849133c14ef5123d01023f0110cbb9fc6f818da053c01277914ae81473430a952  lapack-3.4.2.tar.gz' > lapack-3.4.2.tar.gz.sha512
+echo '887582e5a22e4cde338aa8fec7a89f6dd31f2f02b8842735f00f970f64582333fa03401cea6d01704083403c7e8b7ebc26655468ce930165673b33efa4bcd586  libpng-1.6.3.tar.gz' > libpng-1.6.3.tar.gz.sha512
+echo '990e3a155ca7a9d329c41a43b44a9625f717205e81157c668a8f3f2ad5459ed3fed8c9bd85e7f81c509e0628d2192a262d4aa30c8bfc348bb67ed60a0362505a  matplotlib-1.3.0.tar.gz' > matplotlib-1.3.0.tar.gz.sha512
+echo 'e425778edb0f71c34e719e04561ee3de37feaa1be4d60b94c780aebdbe6d41f8f4ab15103a8bbe8894ebeb228c42f0e2cd41b8db840f8384e1cd7cd2d5b67b97  mercurial-2.7.tar.gz' > mercurial-2.7.tar.gz.sha512
+echo 'a3b8060e415560a868599224449a3af636d24a060f1381990b175dcd12f30249edd181179d23aea06b0c755ff3dc821b7a15ed8840f7855530479587d4d814f4  nose-1.3.0.tar.gz' > nose-1.3.0.tar.gz.sha512
+echo 'd58177f3971b6d07baf6f81a2088ba371c7e43ea64ee7ada261da97c6d725b4bd4927122ac373c55383254e4e31691939276dab08a79a238bfa55172a3eff684  numpy-1.7.1.tar.gz' > numpy-1.7.1.tar.gz.sha512
+echo '9c0a61299779aff613131aaabbc255c8648f0fa7ab1806af53f19fbdcece0c8a68ddca7880d25b926d67ff1b9201954b207919fb09f6a290acb078e8bbed7b68  python-hglib-1.0.tar.gz' > python-hglib-1.0.tar.gz.sha512
+echo 'c65013293dd4049af5db009fdf7b6890a3c6b1e12dd588b58fb5f5a5fef7286935851fb7a530e03ea16f28de48b964e50f48bbf87d34545fd23b80dd4380476b  pyzmq-13.1.0.tar.gz' > pyzmq-13.1.0.tar.gz.sha512
 echo '172f2bc671145ebb0add2669c117863db35851fb3bdb192006cd710d4d038e0037497eb39a6d01091cb923f71a7e8982a77b6e80bf71d6275d5d83a363c8d7e5  rockstar-0.99.6.tar.gz' > rockstar-0.99.6.tar.gz.sha512
-echo 'd4fdd62f2db5285cd133649bd1bfa5175cb9da8304323abd74e0ef1207d55e6152f0f944da1da75f73e9dafb0f3bb14efba3c0526c732c348a653e0bd223ccfa  scipy-0.11.0.tar.gz' > scipy-0.11.0.tar.gz.sha512
-echo '276bd9c061ec9a27d478b33078a86f93164ee2da72210e12e2c9da71dcffeb64767e4460b93f257302b09328eda8655e93c4b9ae85e74472869afbeae35ca71e  blas.tar.gz' > blas.tar.gz.sha512
-echo '8770214491e31f0a7a3efaade90eee7b0eb20a8a6ab635c5f854d78263f59a1849133c14ef5123d01023f0110cbb9fc6f818da053c01277914ae81473430a952  lapack-3.4.2.tar.gz' > lapack-3.4.2.tar.gz.sha512
+echo '80c8e137c3ccba86575d4263e144ba2c4684b94b5cd620e200f094c92d4e118ea6a631d27bdb259b0869771dfaeeae68c0fdd37fdd740b9027ee185026e921d4  scipy-0.12.0.tar.gz' > scipy-0.12.0.tar.gz.sha512
+echo '96f3e51b46741450bc6b63779c10ebb4a7066860fe544385d64d1eda52592e376a589ef282ace2e1df73df61c10eab1a0d793abbdaf770e60289494d4bf3bcb4  sqlite-autoconf-3071700.tar.gz' > sqlite-autoconf-3071700.tar.gz.sha512
+echo '2992baa3edfb4e1842fb642abf0bf0fc0bf56fc183aab8fed6b3c42fbea928fa110ede7fdddea2d63fc5953e8d304b04da433dc811134fadefb1eecc326121b8  sympy-0.7.3.tar.gz' > sympy-0.7.3.tar.gz.sha512
+echo '101544db6c97beeadc5a02b2ef79edefa0a07e129840ace2e4aa451f3976002a273606bcdc12d6cef5c22ff4c1c9dcf60abccfdee4cbef8e3f957cd25c0430cf  tornado-3.1.tar.gz' > tornado-3.1.tar.gz.sha512
+echo '34ffb6aa645f62bd1158a8f2888bf92929ccf90917a6c50ed51ed1240732f498522e164d1536f26480c87ad5457fe614a93bf0e15f2f89b0b168e64a30de68ca  zeromq-3.2.3.tar.gz' > zeromq-3.2.3.tar.gz.sha512
+echo 'ece209d4c7ec0cb58ede791444dc754e0d10811cbbdebe3df61c0fd9f9f9867c1c3ccd5f1827f847c005e24eef34fb5bf87b5d3f894d75da04f1797538290e4a  zlib-1.2.8.tar.gz' > zlib-1.2.8.tar.gz.sha512
 # Individual processes
-[ -z "$HDF5_DIR" ] && get_ytproject hdf5-1.8.9.tar.gz
-[ $INST_ZLIB -eq 1 ] && get_ytproject zlib-1.2.7.tar.gz
-[ $INST_BZLIB -eq 1 ] && get_ytproject bzip2-1.0.6.tar.gz
-[ $INST_PNG -eq 1 ] && get_ytproject libpng-1.6.1.tar.gz
-[ $INST_FTYPE -eq 1 ] && get_ytproject freetype-2.4.11.tar.gz
-[ $INST_SQLITE3 -eq 1 ] && get_ytproject sqlite-autoconf-3071601.tar.gz
-[ $INST_PYX -eq 1 ] && get_ytproject PyX-0.12.1.tar.gz
-[ $INST_0MQ -eq 1 ] && get_ytproject zeromq-3.2.2.tar.gz
-[ $INST_0MQ -eq 1 ] && get_ytproject pyzmq-13.0.2.tar.gz
-[ $INST_0MQ -eq 1 ] && get_ytproject tornado-3.0.tar.gz
-[ $INST_SCIPY -eq 1 ] && get_ytproject scipy-0.11.0.tar.gz
+[ -z "$HDF5_DIR" ] && get_ytproject $HDF5.tar.gz
+[ $INST_ZLIB -eq 1 ] && get_ytproject $ZLIB.tar.gz
+[ $INST_BZLIB -eq 1 ] && get_ytproject $BZLIB.tar.gz
+[ $INST_PNG -eq 1 ] && get_ytproject $PNG.tar.gz
+[ $INST_FTYPE -eq 1 ] && get_ytproject $FREETYPE_VER.tar.gz
+[ $INST_SQLITE3 -eq 1 ] && get_ytproject $SQLITE.tar.gz
+[ $INST_PYX -eq 1 ] && get_ytproject $PYX.tar.gz
+[ $INST_0MQ -eq 1 ] && get_ytproject $ZEROMQ.tar.gz
+[ $INST_0MQ -eq 1 ] && get_ytproject $PYZMQ.tar.gz
+[ $INST_0MQ -eq 1 ] && get_ytproject $TORNADO.tar.gz
+[ $INST_SCIPY -eq 1 ] && get_ytproject $SCIPY.tar.gz
 [ $INST_SCIPY -eq 1 ] && get_ytproject blas.tar.gz
-[ $INST_SCIPY -eq 1 ] && get_ytproject lapack-3.4.2.tar.gz
-get_ytproject Python-2.7.4.tgz
-get_ytproject numpy-1.7.0.tar.gz
-get_ytproject matplotlib-1.2.1.tar.gz
-get_ytproject mercurial-2.5.4.tar.gz
-get_ytproject ipython-0.13.1.tar.gz
-get_ytproject h5py-2.1.2.tar.gz
-get_ytproject Cython-0.18.tar.gz
+[ $INST_SCIPY -eq 1 ] && get_ytproject $LAPACK.tar.gz
+get_ytproject $PYTHON.tgz
+get_ytproject $NUMPY.tar.gz
+get_ytproject $MATPLOTLIB.tar.gz
+get_ytproject $MERCURIAL.tar.gz
+get_ytproject $IPYTHON.tar.gz
+get_ytproject $H5PY.tar.gz
+get_ytproject $CYTHON.tar.gz
 get_ytproject reason-js-20120623.zip
-get_ytproject Forthon-0.8.11.tar.gz
-get_ytproject nose-1.2.1.tar.gz
-get_ytproject python-hglib-0.3.tar.gz
-get_ytproject sympy-0.7.2.tar.gz
-get_ytproject rockstar-0.99.6.tar.gz
+get_ytproject $FORTHON.tar.gz
+get_ytproject $NOSE.tar.gz
+get_ytproject $PYTHON_HGLIB.tar.gz
+get_ytproject $SYMPY.tar.gz
+get_ytproject $ROCKSTAR.tar.gz
 if [ $INST_BZLIB -eq 1 ]
 then
-    if [ ! -e bzip2-1.0.6/done ]
+    if [ ! -e $BZLIB/done ]
     then
-        [ ! -e bzip2-1.0.6 ] && tar xfz bzip2-1.0.6.tar.gz
+        [ ! -e $BZLIB ] && tar xfz $BZLIB.tar.gz
         echo "Installing BZLIB"
-        cd bzip2-1.0.6
+        cd $BZLIB
         if [ `uname` = "Darwin" ]
         then
             if [ -z "${CC}" ]
@@ -634,11 +667,11 @@
 
 if [ $INST_ZLIB -eq 1 ]
 then
-    if [ ! -e zlib-1.2.7/done ]
+    if [ ! -e $ZLIB/done ]
     then
-        [ ! -e zlib-1.2.7 ] && tar xfz zlib-1.2.7.tar.gz
+        [ ! -e $ZLIB ] && tar xfz $ZLIB.tar.gz
         echo "Installing ZLIB"
-        cd zlib-1.2.7
+        cd $ZLIB
         ( ./configure --shared --prefix=${DEST_DIR}/ 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make install 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make clean 2>&1) 1>> ${LOG_FILE} || do_exit
@@ -652,11 +685,11 @@
 
 if [ $INST_PNG -eq 1 ]
 then
-    if [ ! -e libpng-1.6.1/done ]
+    if [ ! -e $PNG/done ]
     then
-        [ ! -e libpng-1.6.1 ] && tar xfz libpng-1.6.1.tar.gz
+        [ ! -e $PNG ] && tar xfz $PNG.tar.gz
         echo "Installing PNG"
-        cd libpng-1.6.1
+        cd $PNG
         ( ./configure CPPFLAGS=-I${DEST_DIR}/include CFLAGS=-I${DEST_DIR}/include --prefix=${DEST_DIR}/ 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make install 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make clean 2>&1) 1>> ${LOG_FILE} || do_exit
@@ -670,13 +703,14 @@
 
 if [ $INST_FTYPE -eq 1 ]
 then
-    if [ ! -e freetype-2.4.11/done ]
+    if [ ! -e $FREETYPE_VER/done ]
     then
-        [ ! -e freetype-2.4.11 ] && tar xfz freetype-2.4.11.tar.gz
+        [ ! -e $FREETYPE_VER ] && tar xfz $FREETYPE_VER.tar.gz
         echo "Installing FreeType2"
-        cd freetype-2.4.11
+        cd $FREETYPE_VER
         ( ./configure CFLAGS=-I${DEST_DIR}/include --prefix=${DEST_DIR}/ 2>&1 ) 1>> ${LOG_FILE} || do_exit
-        ( make install 2>&1 ) 1>> ${LOG_FILE} || do_exit
+        ( make 2>&1 ) 1>> ${LOG_FILE} || do_exit
+		( make install 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make clean 2>&1) 1>> ${LOG_FILE} || do_exit
         touch done
         cd ..
@@ -688,11 +722,11 @@
 
 if [ -z "$HDF5_DIR" ]
 then
-    if [ ! -e hdf5-1.8.9/done ]
+    if [ ! -e $HDF5/done ]
     then
-        [ ! -e hdf5-1.8.9 ] && tar xfz hdf5-1.8.9.tar.gz
+        [ ! -e $HDF5 ] && tar xfz $HDF5.tar.gz
         echo "Installing HDF5"
-        cd hdf5-1.8.9
+        cd $HDF5
         ( ./configure --prefix=${DEST_DIR}/ --enable-shared 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make ${MAKE_PROCS} install 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make clean 2>&1) 1>> ${LOG_FILE} || do_exit
@@ -707,11 +741,11 @@
 
 if [ $INST_SQLITE3 -eq 1 ]
 then
-    if [ ! -e sqlite-autoconf-3071601/done ]
+    if [ ! -e $SQLITE/done ]
     then
-        [ ! -e sqlite-autoconf-3071601 ] && tar xfz sqlite-autoconf-3071601.tar.gz
+        [ ! -e $SQLITE ] && tar xfz $SQLITE.tar.gz
         echo "Installing SQLite3"
-        cd sqlite-autoconf-3071601
+        cd $SQLITE
         ( ./configure --prefix=${DEST_DIR}/ 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make ${MAKE_PROCS} install 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make clean 2>&1) 1>> ${LOG_FILE} || do_exit
@@ -720,11 +754,11 @@
     fi
 fi
 
-if [ ! -e Python-2.7.4/done ]
+if [ ! -e $PYTHON/done ]
 then
     echo "Installing Python.  This may take a while, but don't worry.  yt loves you."
-    [ ! -e Python-2.7.4 ] && tar xfz Python-2.7.4.tgz
-    cd Python-2.7.4
+    [ ! -e $PYTHON ] && tar xfz $PYTHON.tgz
+    cd $PYTHON
     ( ./configure --prefix=${DEST_DIR}/ ${PYCONF_ARGS} 2>&1 ) 1>> ${LOG_FILE} || do_exit
 
     ( make ${MAKE_PROCS} 2>&1 ) 1>> ${LOG_FILE} || do_exit
@@ -739,7 +773,7 @@
 
 if [ $INST_HG -eq 1 ]
 then
-    do_setup_py mercurial-2.5.4
+    do_setup_py $MERCURIAL
     export HG_EXEC=${DEST_DIR}/bin/hg
 else
     # We assume that hg can be found in the path.
@@ -788,9 +822,9 @@
 
 if [ $INST_SCIPY -eq 0 ]
 then
-    do_setup_py numpy-1.7.0 ${NUMPY_ARGS}
+    do_setup_py $NUMPY ${NUMPY_ARGS}
 else
-    if [ ! -e scipy-0.11.0/done ]
+    if [ ! -e $SCIPY/done ]
     then
 	if [ ! -e BLAS/done ]
 	then
@@ -798,17 +832,17 @@
 	    echo "Building BLAS"
 	    cd BLAS
 	    gfortran -O2 -fPIC -fno-second-underscore -c *.f
-	    ar r libfblas.a *.o 1>> ${LOG_FILE}
+	    ar r libfblas.a *.o &>> ${LOG_FILE}
 	    ranlib libfblas.a 1>> ${LOG_FILE}
 	    rm -rf *.o
 	    touch done
 	    cd ..
 	fi
-	if [ ! -e lapack-3.4.2/done ]
+	if [ ! -e $LAPACK/done ]
 	then
-	    tar xfz lapack-3.4.2.tar.gz
+	    tar xfz $LAPACK.tar.gz
 	    echo "Building LAPACK"
-	    cd lapack-3.4.2/
+	    cd $LAPACK/
 	    cp INSTALL/make.inc.gfortran make.inc
 	    make lapacklib OPTS="-fPIC -O2" NOOPT="-fPIC -O0" CFLAGS=-fPIC LDFLAGS=-fPIC 1>> ${LOG_FILE} || do_exit
 	    touch done
@@ -816,9 +850,9 @@
 	fi
     fi
     export BLAS=$PWD/BLAS/libfblas.a
-    export LAPACK=$PWD/lapack-3.4.2/liblapack.a
-    do_setup_py numpy-1.7.0 ${NUMPY_ARGS}
-    do_setup_py scipy-0.11.0 ${NUMPY_ARGS}
+    export LAPACK=$PWD/$LAPACK/liblapack.a
+    do_setup_py $NUMPY ${NUMPY_ARGS}
+    do_setup_py $SCIPY ${NUMPY_ARGS}
 fi
 
 if [ -n "${MPL_SUPP_LDFLAGS}" ]
@@ -840,10 +874,10 @@
     echo "Setting CFLAGS ${CFLAGS}"
 fi
 # Now we set up the basedir for matplotlib:
-mkdir -p ${DEST_DIR}/src/matplotlib-1.2.1
-echo "[directories]" >> ${DEST_DIR}/src/matplotlib-1.2.1/setup.cfg
-echo "basedirlist = ${DEST_DIR}" >> ${DEST_DIR}/src/matplotlib-1.2.1/setup.cfg
-do_setup_py matplotlib-1.2.1
+mkdir -p ${DEST_DIR}/src/$MATPLOTLIB
+echo "[directories]" >> ${DEST_DIR}/src/$MATPLOTLIB/setup.cfg
+echo "basedirlist = ${DEST_DIR}" >> ${DEST_DIR}/src/$MATPLOTLIB/setup.cfg
+do_setup_py $MATPLOTLIB
 if [ -n "${OLD_LDFLAGS}" ]
 then
     export LDFLAG=${OLD_LDFLAGS}
@@ -855,36 +889,36 @@
 # Now we do our IPython installation, which has two optional dependencies.
 if [ $INST_0MQ -eq 1 ]
 then
-    if [ ! -e zeromq-3.2.2/done ]
+    if [ ! -e $ZEROMQ/done ]
     then
-        [ ! -e zeromq-3.2.2 ] && tar xfz zeromq-3.2.2.tar.gz
+        [ ! -e $ZEROMQ ] && tar xfz $ZEROMQ.tar.gz
         echo "Installing ZeroMQ"
-        cd zeromq-3.2.2
+        cd $ZEROMQ
         ( ./configure --prefix=${DEST_DIR}/ 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make install 2>&1 ) 1>> ${LOG_FILE} || do_exit
         ( make clean 2>&1) 1>> ${LOG_FILE} || do_exit
         touch done
         cd ..
     fi
-    do_setup_py pyzmq-13.0.2 --zmq=${DEST_DIR}
-    do_setup_py tornado-3.0
+    do_setup_py $PYZMQ --zmq=${DEST_DIR}
+    do_setup_py $TORNADO
 fi
 
-do_setup_py ipython-0.13.1
-do_setup_py h5py-2.1.2
-do_setup_py Cython-0.18
-do_setup_py Forthon-0.8.11
-do_setup_py nose-1.2.1
-do_setup_py python-hglib-0.3
-do_setup_py sympy-0.7.2
-[ $INST_PYX -eq 1 ] && do_setup_py PyX-0.12.1
+do_setup_py $IPYTHON
+do_setup_py $H5PY
+do_setup_py $CYTHON
+do_setup_py $FORTHON
+do_setup_py $NOSE
+do_setup_py $PYTHON_HGLIB
+do_setup_py $SYMPY
+[ $INST_PYX -eq 1 ] && do_setup_py $PYX
 
 # Now we build Rockstar and set its environment variable.
 if [ $INST_ROCKSTAR -eq 1 ]
 then
     if [ ! -e Rockstar/done ]
     then
-        [ ! -e Rockstar ] && tar xfz rockstar-0.99.6.tar.gz
+        [ ! -e Rockstar ] && tar xfz $ROCKSTAR.tar.gz
         echo "Building Rockstar"
         cd Rockstar
         ( make lib 2>&1 ) 1>> ${LOG_FILE} || do_exit

diff -r 8ddc4dd0d42e7b6fcbbcc8f9be7e9dae627bf970 -r a820a4081ce82cd759d13fc46c216bae3066cbc5 yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -62,7 +62,7 @@
     notebook_password = '',
     answer_testing_tolerance = '3',
     answer_testing_bitwise = 'False',
-    gold_standard_filename = 'gold009',
+    gold_standard_filename = 'gold010',
     local_standard_filename = 'local001',
     sketchfab_api_key = 'None'
     )

diff -r 8ddc4dd0d42e7b6fcbbcc8f9be7e9dae627bf970 -r a820a4081ce82cd759d13fc46c216bae3066cbc5 yt/visualization/volume_rendering/transfer_functions.py
--- a/yt/visualization/volume_rendering/transfer_functions.py
+++ b/yt/visualization/volume_rendering/transfer_functions.py
@@ -236,8 +236,15 @@
     this is fine.  However, more complicated schema are possible by using
     this object.  For instance, density-weighted emission that produces
     colors based on the temperature of the fluid.
+
+    Parameters
+    ----------
+    grey_opacity : bool
+        Should opacity be calculated on a channel-by-channel basis, or
+        overall?  Useful for opaque renderings. Default: False
+ 
     """
-    def __init__(self):
+    def __init__(self, grey_opacity=False):
         self.n_field_tables = 0
         self.tables = [] # Tables are interpolation tables
         self.field_ids = [0] * 6 # This correlates fields with tables
@@ -246,6 +253,7 @@
         self.weight_table_ids = [-1] * 6
         self.grad_field = -1
         self.light_source_v = self.light_source_c = np.zeros(3, 'float64')
+        self.grey_opacity = grey_opacity
 
     def add_field_table(self, table, field_id, weight_field_id = -1,
                         weight_table_id = -1):
@@ -803,6 +811,7 @@
             self.link_channels(i+3, i+3)
 
         self._normalize()
+        self.grey_opacity = False
 
     def _normalize(self):
         fmax  = np.array([f.y for f in self.tables[:3]])


https://bitbucket.org/yt_analysis/yt-3.0/commits/c0ffdcc604f7/
Changeset:   c0ffdcc604f7
Branch:      yt
User:        chummels
Date:        2013-08-16 23:16:54
Summary:     Updating docstrings of annotate_grids callback to match others for use in docs.
Affected #:  1 file

diff -r a820a4081ce82cd759d13fc46c216bae3066cbc5 -r c0ffdcc604f77380300b46474eb421cb8e0b555f yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -343,44 +343,13 @@
                  min_level=None, max_level=None, cmap='B-W LINEAR_r'):
 
     Draws grids on an existing PlotWindow object.
-
-    Parameters
-    ----------
-    alpha: float, optional
-        The alpha value for the grids being drawn.  Used to control
-        how bright the grid lines are with respect to the image.
-        Default : 0.7
-
-    cmap : string, optional
-        Colormap to be used mapping grid levels to colors.  If 
-        cmap is set to None, will default to all black grid boxes.
-        The default colormap was chosen to give shades of white to black
-        as the refinement level increases.
-        Default : 'B-W LINEAR_r'
-
-    min_pix : int, optional
-        If a grid patch is smaller than min_pix pixels in size in image
-        space, it will not be displayed.
-        Default : 1
-    
-    min_pix_ids : int, optional
-        If a grid patch is smaller than min_pix_ids pixels in size in 
-        image space, it will not be labeled with an id (only applies
-        when using the *draw_ids* kwarg).
-        Default : 20
-
-    draw_ids : bool, optional
-        When set, labels each grid with ID number.
-        Default : False
-
-    periodic : bool, optional
-        Retains periodic behavior of grids at volume boundaries.
-        Default : False
-
-    min_level, max_level : int, optional
-        Optional parameters to specify the min and max level grid boxes
-        to overplot on the image.
-
+    Adds grid boundaries to a plot, optionally with alpha-blending. By default, 
+    colors different levels of grids with different colors going from white to
+    black, but you can change to any arbitrary colormap with cmap keyword 
+    (or all black cells for all levels with cmap=None).  Cuttoff for display is at 
+    min_pix wide. draw_ids puts the grid id in the corner of the grid. 
+    (Not so great in projections...).  One can set min and maximum level of
+    grids to display.
     """
     _type_name = "grids"
     def __init__(self, alpha=0.7, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 


https://bitbucket.org/yt_analysis/yt-3.0/commits/04f2aa00bfa6/
Changeset:   04f2aa00bfa6
Branch:      yt
User:        MatthewTurk
Date:        2013-08-20 21:03:33
Summary:     Merged in chummels/yt (pull request #571)

Adding shaded_level kwarg to annotate_grids
Affected #:  4 files

diff -r 5cd76d510e52558fdbdff615e0a904a8d352a673 -r 04f2aa00bfa6e414e9e1250aee03a275327f6466 yt/analysis_modules/halo_finding/halo_objects.py
--- a/yt/analysis_modules/halo_finding/halo_objects.py
+++ b/yt/analysis_modules/halo_finding/halo_objects.py
@@ -1061,8 +1061,9 @@
     def __init__(self, data_source, dm_only=True, redshift=-1):
         """
         Run hop on *data_source* with a given density *threshold*.  If
-        *dm_only* is True (default), only run it on the dark matter particles, otherwise
-        on all particles.  Returns an iterable collection of *HopGroup* items.
+        *dm_only* is True (default), only run it on the dark matter particles, 
+        otherwise on all particles.  Returns an iterable collection of 
+        *HopGroup* items.
         """
         self._data_source = data_source
         self.dm_only = dm_only

diff -r 5cd76d510e52558fdbdff615e0a904a8d352a673 -r 04f2aa00bfa6e414e9e1250aee03a275327f6466 yt/visualization/_colormap_data.py
--- a/yt/visualization/_colormap_data.py
+++ b/yt/visualization/_colormap_data.py
@@ -7798,3 +7798,11 @@
 color_map_luts['Rainbow18'] = color_map_luts['idl38']
 color_map_luts['Rainbow + white'] = color_map_luts['idl39']
 color_map_luts['Rainbow + black'] = color_map_luts['idl40']
+
+# Create a reversed LUT for each of the above defined LUTs
+# and append a "_r" (for reversal. consistent with MPL convention).
+# So for example, the reversal of "Waves" is "Waves_r"
+temp = {}
+for k,v in color_map_luts.iteritems():
+    temp[k+"_r"] = (v[0][::-1], v[1][::-1], v[2][::-1], v[3][::-1])
+color_map_luts.update(temp)

diff -r 5cd76d510e52558fdbdff615e0a904a8d352a673 -r 04f2aa00bfa6e414e9e1250aee03a275327f6466 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -44,6 +44,7 @@
     sec_per_Gyr, sec_per_Myr, \
     sec_per_kyr, sec_per_year, \
     sec_per_day, sec_per_hr
+from yt.visualization.image_writer import apply_colormap
 
 import _MPL
 
@@ -175,7 +176,8 @@
 
 class QuiverCallback(PlotCallback):
     """
-    annotate_quiver(field_x, field_y, factor, scale=None, scale_units=None, normalize=False):
+    annotate_quiver(field_x, field_y, factor=16, scale=None, scale_units=None, 
+                    normalize=False, bv_x=0, bv_y=0):
 
     Adds a 'quiver' plot to any plot, using the *field_x* and *field_y*
     from the associated data, skipping every *factor* datapoints
@@ -229,8 +231,8 @@
 
 class ContourCallback(PlotCallback):
     """
-    annotate_contour(self, field, ncont=5, factor=4, take_log=None, clim=None,
-                     plot_args = None):
+    annotate_contour(field, ncont=5, factor=4, take_log=None, clim=None,
+                     plot_args=None, label=False, label_args=None):
 
     Add contours in *field* to the plot.  *ncont* governs the number of
     contours generated, *factor* governs the number of points used in the
@@ -337,18 +339,21 @@
 
 class GridBoundaryCallback(PlotCallback):
     """
-    annotate_grids(alpha=1.0, min_pix=1, draw_ids=False, periodic=True)
+    annotate_grids(alpha=0.7, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
+                 min_level=None, max_level=None, cmap='B-W LINEAR_r'):
 
-    Adds grid boundaries to a plot, optionally with *alpha*-blending.
-    Cuttoff for display is at *min_pix* wide.
-    *draw_ids* puts the grid id in the corner of the grid.  (Not so great in projections...)
-    Grids must be wider than *min_pix_ids* otherwise the ID will not be drawn.  If *min_level* 
-    is specified, only draw grids at or above min_level.  If *max_level* is specified, only 
-    draw grids at or below max_level.
+    Draws grids on an existing PlotWindow object.
+    Adds grid boundaries to a plot, optionally with alpha-blending. By default, 
+    colors different levels of grids with different colors going from white to
+    black, but you can change to any arbitrary colormap with cmap keyword 
+    (or all black cells for all levels with cmap=None).  Cuttoff for display is at 
+    min_pix wide. draw_ids puts the grid id in the corner of the grid. 
+    (Not so great in projections...).  One can set min and maximum level of
+    grids to display.
     """
     _type_name = "grids"
-    def __init__(self, alpha=1.0, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
-                 min_level=None, max_level=None):
+    def __init__(self, alpha=0.7, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
+                 min_level=None, max_level=None, cmap='B-W LINEAR_r'):
         PlotCallback.__init__(self)
         self.alpha = alpha
         self.min_pix = min_pix
@@ -357,6 +362,7 @@
         self.periodic = periodic
         self.min_level = min_level
         self.max_level = max_level
+        self.cmap = cmap
 
     def __call__(self, plot):
         x0, x1 = plot.xlim
@@ -376,13 +382,13 @@
             pxs, pys = np.mgrid[0:0:1j,0:0:1j]
         GLE = plot.data.grid_left_edge
         GRE = plot.data.grid_right_edge
-        grid_levels = plot.data.grid_levels[:,0]
+        levels = plot.data.grid_levels[:,0]
         min_level = self.min_level
         max_level = self.max_level
+        if max_level is None:
+            max_level = plot.data.pf.h.max_level
         if min_level is None:
             min_level = 0
-        if max_level is None:
-            max_level = plot.data.pf.h.max_level
 
         for px_off, py_off in zip(pxs.ravel(), pys.ravel()):
             pxo = px_off * dom[px_index]
@@ -393,19 +399,28 @@
             right_edge_y = (GRE[:,py_index]+pyo-y0)*dy + yy0
             visible =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix ) & \
                        ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix ) & \
-                       ( grid_levels >= min_level) & \
-                       ( grid_levels <= max_level)
+                       ( levels >= min_level) & \
+                       ( levels <= max_level)
+
+            if self.cmap is not None: 
+                edgecolors = apply_colormap(levels[(levels <= max_level) & (levels >= min_level)]*1.0,
+                                  color_bounds=[0,plot.data.pf.h.max_level],
+                                  cmap_name=self.cmap)[0,:,:]*1.0/255.
+                edgecolors[:,3] = self.alpha
+            else:
+                edgecolors = (0.0,0.0,0.0,self.alpha)
+
             if visible.nonzero()[0].size == 0: continue
             verts = np.array(
                 [(left_edge_x, left_edge_x, right_edge_x, right_edge_x),
                  (left_edge_y, right_edge_y, right_edge_y, left_edge_y)])
             verts=verts.transpose()[visible,:,:]
-            edgecolors = (0.0,0.0,0.0,self.alpha)
             grid_collection = matplotlib.collections.PolyCollection(
                 verts, facecolors="none",
                 edgecolors=edgecolors)
             plot._axes.hold(True)
             plot._axes.add_collection(grid_collection)
+
             if self.draw_ids:
                 visible_ids =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix_ids ) & \
                                ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix_ids )

diff -r 5cd76d510e52558fdbdff615e0a904a8d352a673 -r 04f2aa00bfa6e414e9e1250aee03a275327f6466 yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -277,7 +277,7 @@
                    max_level=None):
         r"""Draws Grids on an existing volume rendering.
 
-        By mapping grid level to a color, drawes edges of grids on 
+        By mapping grid level to a color, draws edges of grids on 
         a volume rendering using the camera orientation.
 
         Parameters


https://bitbucket.org/yt_analysis/yt-3.0/commits/456f4ec6d279/
Changeset:   456f4ec6d279
Branch:      yt
User:        chummels
Date:        2013-08-20 20:55:01
Summary:     Adding in show_colormaps function which enables the user to see what colormaps are available in yt.
Affected #:  1 file

diff -r c0ffdcc604f77380300b46474eb421cb8e0b555f -r 456f4ec6d2796fa6151511fac6808d88d2e87c11 yt/visualization/color_maps.py
--- a/yt/visualization/color_maps.py
+++ b/yt/visualization/color_maps.py
@@ -145,3 +145,57 @@
     b = cmap._lut[:-3, 2]
     a = np.ones(b.shape)
     return [r, g, b, a]
+
+def show_colormaps(subset = "all", filename=None):
+    """
+    Displays the colormaps available to yt.  Note, most functions can use
+    both the matplotlib and the native yt colormaps; however, there are 
+    some special functions existing within image_writer.py (e.g. write_image()
+    write_fits(), write_bitmap(), etc.), which cannot access the matplotlib
+    colormaps.
+
+    In addition to the colormaps listed, one can access the reverse of each 
+    colormap by appending a "_r" to any map.
+    
+    Parameters
+    ----------
+
+    subset : string, opt
+
+        valid values : "all", "yt_native"
+        default : "all"
+
+        As mentioned above, a few functions can only access yt_native 
+        colormaps.  To display only the yt_native colormaps, set this
+        to "yt_native".  
+
+    filename : string, opt
+
+        default: None
+
+        If filename is set, then it will save the colormaps to an output
+        file.  If it is not set, it will "show" the result interactively.
+    """
+    import pylab as pl
+
+    pl.rc('text', usetex=False)
+    a=np.outer(np.arange(0,1,0.01), np.ones(10))
+    if (subset == "all"):
+        maps = [ m for m in pl.cm.datad if (not m.startswith("idl")) & (not m.endswith("_r"))]
+    if (subset == "yt_native"):
+        maps = [ m for m in _cm.color_map_luts if (not m.startswith("idl")) & (not m.endswith("_r"))]
+    maps = np.unique(maps)
+    maps.sort()
+    # scale the image size by the number of cmaps
+    pl.figure(figsize=(2.*len(maps)/10.,6))
+    pl.subplots_adjust(top=0.7,bottom=0.05,left=0.01,right=0.99)
+    l = len(maps)+1
+    for i,m in enumerate(maps):
+        pl.subplot(1,l,i+1)
+        pl.axis("off")
+        pl.imshow(a, aspect='auto',cmap=pl.get_cmap(m),origin="lower")      
+        pl.title(m,rotation=90, fontsize=10, verticalalignment='bottom')
+    if filename is not None:
+        pl.savefig(filename, dpi=100, facecolor='gray') 
+    else:  
+        pl.show()


https://bitbucket.org/yt_analysis/yt-3.0/commits/e3b5758d1ef6/
Changeset:   e3b5758d1ef6
Branch:      yt
User:        chummels
Date:        2013-08-20 20:57:35
Summary:     Adding show_colormaps to visualization and mods api's.
Affected #:  2 files

diff -r 456f4ec6d2796fa6151511fac6808d88d2e87c11 -r e3b5758d1ef6519b97274dcbe42c062568ecb31d yt/mods.py
--- a/yt/mods.py
+++ b/yt/mods.py
@@ -131,7 +131,8 @@
     get_multi_plot, FixedResolutionBuffer, ObliqueFixedResolutionBuffer, \
     callback_registry, write_bitmap, write_image, annotate_image, \
     apply_colormap, scale_image, write_projection, write_fits, \
-    SlicePlot, OffAxisSlicePlot, ProjectionPlot, OffAxisProjectionPlot
+    SlicePlot, OffAxisSlicePlot, ProjectionPlot, OffAxisProjectionPlot, \
+    show_colormaps
 
 from yt.visualization.volume_rendering.api import \
     ColorTransferFunction, PlanckTransferFunction, ProjectionTransferFunction, \

diff -r 456f4ec6d2796fa6151511fac6808d88d2e87c11 -r e3b5758d1ef6519b97274dcbe42c062568ecb31d yt/visualization/api.py
--- a/yt/visualization/api.py
+++ b/yt/visualization/api.py
@@ -29,7 +29,8 @@
 """
 
 from color_maps import \
-    add_cmap
+    add_cmap, \
+    show_colormaps
 
 from plot_collection import \
     PlotCollection, \


https://bitbucket.org/yt_analysis/yt-3.0/commits/0b358633485b/
Changeset:   0b358633485b
Branch:      yt
User:        chummels
Date:        2013-08-20 20:57:52
Summary:     Merging.
Affected #:  2 files

diff -r e3b5758d1ef6519b97274dcbe42c062568ecb31d -r 0b358633485b5c32c3960b9168afa707490e9f3f doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -832,8 +832,8 @@
 	    echo "Building BLAS"
 	    cd BLAS
 	    gfortran -O2 -fPIC -fno-second-underscore -c *.f
-	    ar r libfblas.a *.o &>> ${LOG_FILE}
-	    ranlib libfblas.a 1>> ${LOG_FILE}
+	    ( ar r libfblas.a *.o 2>&1 ) 1>> ${LOG_FILE}
+	    ( ranlib libfblas.a 2>&1 ) 1>> ${LOG_FILE}
 	    rm -rf *.o
 	    touch done
 	    cd ..
@@ -844,7 +844,7 @@
 	    echo "Building LAPACK"
 	    cd $LAPACK/
 	    cp INSTALL/make.inc.gfortran make.inc
-	    make lapacklib OPTS="-fPIC -O2" NOOPT="-fPIC -O0" CFLAGS=-fPIC LDFLAGS=-fPIC 1>> ${LOG_FILE} || do_exit
+	    ( make lapacklib OPTS="-fPIC -O2" NOOPT="-fPIC -O0" CFLAGS=-fPIC LDFLAGS=-fPIC 2>&1 ) 1>> ${LOG_FILE} || do_exit
 	    touch done
 	    cd ..
 	fi
@@ -943,10 +943,10 @@
 touch done
 cd $MY_PWD
 
-if !(${DEST_DIR}/bin/python2.7 -c "import readline" >> ${LOG_FILE})
+if !( ( ${DEST_DIR}/bin/python2.7 -c "import readline" 2>&1 )>> ${LOG_FILE})
 then
     echo "Installing pure-python readline"
-    ${DEST_DIR}/bin/pip install readline 1>> ${LOG_FILE}
+    ( ${DEST_DIR}/bin/pip install readline 2>&1 ) 1>> ${LOG_FILE}
 fi
 
 if [ $INST_ENZO -eq 1 ]

diff -r e3b5758d1ef6519b97274dcbe42c062568ecb31d -r 0b358633485b5c32c3960b9168afa707490e9f3f yt/frontends/athena/io.py
--- a/yt/frontends/athena/io.py
+++ b/yt/frontends/athena/io.py
@@ -68,9 +68,9 @@
                 data = data[2::3].reshape(grid_dims,order='F').copy()
         f.close()
         if grid.pf.field_ordering == 1:
-            return data.T
+            return data.T.astype("float64")
         else:
-            return data
+            return data.astype("float64")
 
     def _read_data_slice(self, grid, field, axis, coord):
         sl = [slice(None), slice(None), slice(None)]


https://bitbucket.org/yt_analysis/yt-3.0/commits/c33de5552b02/
Changeset:   c33de5552b02
Branch:      yt
User:        chummels
Date:        2013-08-20 21:33:16
Summary:     Merging.
Affected #:  0 files



https://bitbucket.org/yt_analysis/yt-3.0/commits/1b696a4c09d8/
Changeset:   1b696a4c09d8
Branch:      yt
User:        chummels
Date:        2013-08-20 21:55:49
Summary:     Implementing the two PR suggestions by Matt.
Affected #:  1 file

diff -r c33de5552b02e41723ad80b01424843f6553ea88 -r 1b696a4c09d8fab667a676fc9e0c36542e60219a yt/visualization/color_maps.py
--- a/yt/visualization/color_maps.py
+++ b/yt/visualization/color_maps.py
@@ -178,13 +178,12 @@
     """
     import pylab as pl
 
-    pl.rc('text', usetex=False)
     a=np.outer(np.arange(0,1,0.01), np.ones(10))
     if (subset == "all"):
         maps = [ m for m in pl.cm.datad if (not m.startswith("idl")) & (not m.endswith("_r"))]
     if (subset == "yt_native"):
         maps = [ m for m in _cm.color_map_luts if (not m.startswith("idl")) & (not m.endswith("_r"))]
-    maps = np.unique(maps)
+    maps = list(set(maps))
     maps.sort()
     # scale the image size by the number of cmaps
     pl.figure(figsize=(2.*len(maps)/10.,6))


https://bitbucket.org/yt_analysis/yt-3.0/commits/47ea9dca9f23/
Changeset:   47ea9dca9f23
Branch:      yt
User:        xarthisius
Date:        2013-08-19 13:51:27
Summary:     Clean temporary files in test_image_array
Affected #:  1 file

diff -r 0bd09ebbc6c1fd8fac4a7ef51c5ae154664c3658 -r 47ea9dca9f2397b896cbca70143b9a1c51618e3f yt/data_objects/tests/test_image_array.py
--- a/yt/data_objects/tests/test_image_array.py
+++ b/yt/data_objects/tests/test_image_array.py
@@ -1,130 +1,94 @@
-from yt.testing import *
-from yt.data_objects.image_array import ImageArray
 import numpy as np
 import os
 import tempfile
 import shutil
+import unittest
+from yt.data_objects.image_array import ImageArray
+from yt.testing import \
+    assert_equal
+
 
 def setup():
     from yt.config import ytcfg
-    ytcfg["yt","__withintesting"] = "True"
-    np.seterr(all = 'ignore')
+    ytcfg["yt", "__withintesting"] = "True"
+    np.seterr(all='ignore')
+
+
+def dummy_image(kstep, nlayers):
+    im = np.zeros([64, 128, nlayers])
+    for i in xrange(im.shape[0]):
+        for k in xrange(im.shape[2]):
+            im[i, :, k] = np.linspace(0.0, kstep * k, im.shape[1])
+    return im
+
 
 def test_rgba_rescale():
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-    im_arr = ImageArray(im)
+    im_arr = ImageArray(dummy_image(10.0, 4))
 
     new_im = im_arr.rescale(inline=False)
-    yield assert_equal, im_arr[:,:,:3].max(), 2*10.
-    yield assert_equal, im_arr[:,:,3].max(), 3*10.
-    yield assert_equal, new_im[:,:,:3].sum(axis=2).max(), 1.0 
-    yield assert_equal, new_im[:,:,3].max(), 1.0
+    yield assert_equal, im_arr[:, :, :3].max(), 2 * 10.
+    yield assert_equal, im_arr[:, :, 3].max(), 3 * 10.
+    yield assert_equal, new_im[:, :, :3].sum(axis=2).max(), 1.0
+    yield assert_equal, new_im[:, :, 3].max(), 1.0
 
     im_arr.rescale()
-    yield assert_equal, im_arr[:,:,:3].sum(axis=2).max(), 1.0
-    yield assert_equal, im_arr[:,:,3].max(), 1.0
+    yield assert_equal, im_arr[:, :, :3].sum(axis=2).max(), 1.0
+    yield assert_equal, im_arr[:, :, 3].max(), 1.0
 
-def test_image_array_hdf5():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
 
-    im = np.zeros([64,128,3])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,0.3*k, im.shape[1])
+class TestImageArray(unittest.TestCase):
 
-    myinfo = {'field':'dinosaurs', 'east_vector':np.array([1.,0.,0.]), 
-        'north_vector':np.array([0.,0.,1.]), 'normal_vector':np.array([0.,1.,0.]),  
-        'width':0.245, 'units':'cm', 'type':'rendering'}
+    tmpdir = None
+    curdir = None
 
-    im_arr = ImageArray(im, info=myinfo)
-    im_arr.save('test_3d_ImageArray')
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp()
+        self.curdir = os.getcwd()
+        os.chdir(self.tmpdir)
 
-    im = np.zeros([64,128])
-    for i in xrange(im.shape[0]):
-        im[i,:] = np.linspace(0.,0.3*k, im.shape[1])
+    def test_image_array_hdf5(self):
+        myinfo = {'field': 'dinosaurs', 'east_vector': np.array([1., 0., 0.]),
+                  'north_vector': np.array([0., 0., 1.]),
+                  'normal_vector': np.array([0., 1., 0.]),
+                  'width': 0.245, 'units': 'cm', 'type': 'rendering'}
 
-    myinfo = {'field':'dinosaurs', 'east_vector':np.array([1.,0.,0.]), 
-        'north_vector':np.array([0.,0.,1.]), 'normal_vector':np.array([0.,1.,0.]),  
-        'width':0.245, 'units':'cm', 'type':'rendering'}
+        im_arr = ImageArray(dummy_image(0.3, 3), info=myinfo)
+        im_arr.save('test_3d_ImageArray')
 
-    im_arr = ImageArray(im, info=myinfo)
-    im_arr.save('test_2d_ImageArray')
+        im = np.zeros([64, 128])
+        for i in xrange(im.shape[0]):
+            im[i, :] = np.linspace(0., 0.3 * 2, im.shape[1])
 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
+        myinfo = {'field': 'dinosaurs', 'east_vector': np.array([1., 0., 0.]),
+                  'north_vector': np.array([0., 0., 1.]),
+                  'normal_vector': np.array([0., 1., 0.]),
+                  'width': 0.245, 'units': 'cm', 'type': 'rendering'}
 
-def test_image_array_rgb_png():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+        im_arr = ImageArray(im, info=myinfo)
+        im_arr.save('test_2d_ImageArray')
 
-    im = np.zeros([64,128,3])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
+    def test_image_array_rgb_png(self):
+        im_arr = ImageArray(dummy_image(10.0, 3))
+        im_arr.write_png('standard.png')
 
-    im_arr = ImageArray(im)
-    im_arr.write_png('standard.png')
+    def test_image_array_rgba_png(self):
+        im_arr = ImageArray(dummy_image(10.0, 4))
+        im_arr.write_png('standard.png')
+        im_arr.write_png('non-scaled.png', rescale=False)
+        im_arr.write_png('black_bg.png', background='black')
+        im_arr.write_png('white_bg.png', background='white')
+        im_arr.write_png('green_bg.png', background=[0., 1., 0., 1.])
+        im_arr.write_png('transparent_bg.png', background=None)
 
-def test_image_array_rgba_png():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+    def test_image_array_background(self):
+        im_arr = ImageArray(dummy_image(10.0, 4))
+        im_arr.rescale()
+        new_im = im_arr.add_background_color([1., 0., 0., 1.], inline=False)
+        new_im.write_png('red_bg.png')
+        im_arr.add_background_color('black')
+        im_arr.write_png('black_bg2.png')
 
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-
-    im_arr = ImageArray(im)
-    im_arr.write_png('standard.png')
-    im_arr.write_png('non-scaled.png', rescale=False)
-    im_arr.write_png('black_bg.png', background='black')
-    im_arr.write_png('white_bg.png', background='white')
-    im_arr.write_png('green_bg.png', background=[0.,1.,0.,1.])
-    im_arr.write_png('transparent_bg.png', background=None)
-
-
-def test_image_array_background():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
-
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-
-    im_arr = ImageArray(im)
-    im_arr.rescale()
-    new_im = im_arr.add_background_color([1.,0.,0.,1.], inline=False)
-    new_im.write_png('red_bg.png')
-    im_arr.add_background_color('black')
-    im_arr.write_png('black_bg2.png')
- 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
-
-
-
-
-
-
-
-
-
-
-
-
-
+    def tearDown(self):
+        os.chdir(self.curdir)
+        # clean up
+        shutil.rmtree(self.tmpdir)


https://bitbucket.org/yt_analysis/yt-3.0/commits/ee60b2894117/
Changeset:   ee60b2894117
Branch:      yt
User:        xarthisius
Date:        2013-08-19 15:25:31
Summary:     Move file cleanup to 'finally' clause
Affected #:  2 files

diff -r 47ea9dca9f2397b896cbca70143b9a1c51618e3f -r ee60b2894117d89ca0ba2a5b5dfa057df30d6166 yt/utilities/grid_data_format/tests/test_writer.py
--- a/yt/utilities/grid_data_format/tests/test_writer.py
+++ b/yt/utilities/grid_data_format/tests/test_writer.py
@@ -50,17 +50,18 @@
     tmpdir = tempfile.mkdtemp()
     tmpfile = os.path.join(tmpdir, 'test_gdf.h5')
 
-    test_pf = fake_random_pf(64)
-    write_to_gdf(test_pf, tmpfile, data_author=TEST_AUTHOR,
-                 data_comment=TEST_COMMENT)
-    del test_pf
+    try:
+        test_pf = fake_random_pf(64)
+        write_to_gdf(test_pf, tmpfile, data_author=TEST_AUTHOR,
+                     data_comment=TEST_COMMENT)
+        del test_pf
+        assert isinstance(load(tmpfile), GDFStaticOutput)
 
-    assert isinstance(load(tmpfile), GDFStaticOutput)
+        h5f = h5.File(tmpfile, 'r')
+        gdf = h5f['gridded_data_format'].attrs
+        assert_equal(gdf['data_author'], TEST_AUTHOR)
+        assert_equal(gdf['data_comment'], TEST_COMMENT)
+        h5f.close()
 
-    h5f = h5.File(tmpfile, 'r')
-    gdf = h5f['gridded_data_format'].attrs
-    assert_equal(gdf['data_author'], TEST_AUTHOR)
-    assert_equal(gdf['data_comment'], TEST_COMMENT)
-    h5f.close()
-
-    shutil.rmtree(tmpdir)
+    finally:
+        shutil.rmtree(tmpdir)

diff -r 47ea9dca9f2397b896cbca70143b9a1c51618e3f -r ee60b2894117d89ca0ba2a5b5dfa057df30d6166 yt/utilities/lib/setup.py
--- a/yt/utilities/lib/setup.py
+++ b/yt/utilities/lib/setup.py
@@ -20,36 +20,37 @@
     # Create a temporary directory
     tmpdir = tempfile.mkdtemp()
     curdir = os.getcwd()
-    os.chdir(tmpdir)
+    exit_code = 1
 
-    # Get compiler invocation
-    compiler = os.getenv('CC', 'cc')
+    try:
+        os.chdir(tmpdir)
 
-    # Attempt to compile a test script.
-    # See http://openmp.org/wp/openmp-compilers/
-    filename = r'test.c'
-    file = open(filename,'w', 0)
-    file.write(
-        "#include <omp.h>\n"
-        "#include <stdio.h>\n"
-        "int main() {\n"
-        "#pragma omp parallel\n"
-        "printf(\"Hello from thread %d, nthreads %d\\n\", omp_get_thread_num(), omp_get_num_threads());\n"
-        "}"
-        )
-    with open(os.devnull, 'w') as fnull:
-        exit_code = subprocess.call([compiler, '-fopenmp', filename],
-                                    stdout=fnull, stderr=fnull)
+        # Get compiler invocation
+        compiler = os.getenv('CC', 'cc')
 
-    # Clean up
-    file.close()
-    os.chdir(curdir)
-    shutil.rmtree(tmpdir)
+        # Attempt to compile a test script.
+        # See http://openmp.org/wp/openmp-compilers/
+        filename = r'test.c'
+        file = open(filename,'w', 0)
+        file.write(
+            "#include <omp.h>\n"
+            "#include <stdio.h>\n"
+            "int main() {\n"
+            "#pragma omp parallel\n"
+            "printf(\"Hello from thread %d, nthreads %d\\n\", omp_get_thread_num(), omp_get_num_threads());\n"
+            "}"
+            )
+        with open(os.devnull, 'w') as fnull:
+            exit_code = subprocess.call([compiler, '-fopenmp', filename],
+                                        stdout=fnull, stderr=fnull)
 
-    if exit_code == 0:
-        return True
-    else:
-        return False
+        # Clean up
+        file.close()
+    finally:
+        os.chdir(curdir)
+        shutil.rmtree(tmpdir)
+
+    return exit_code == 0
 
 def configuration(parent_package='',top_path=None):
     from numpy.distutils.misc_util import Configuration


https://bitbucket.org/yt_analysis/yt-3.0/commits/e17e82bf3222/
Changeset:   e17e82bf3222
Branch:      yt
User:        xarthisius
Date:        2013-08-19 15:35:58
Summary:     Bundle nose-parameterized (https://github.com/wolever/nose-parameterized) and six (https://bitbucket.org/gutworth/six) with yt
Affected #:  4 files

diff -r ee60b2894117d89ca0ba2a5b5dfa057df30d6166 -r e17e82bf3222ba96d300b78c6f1ed313e58656ce yt/extern/__init__.py
--- /dev/null
+++ b/yt/extern/__init__.py
@@ -0,0 +1,4 @@
+"""
+This packages contains python packages that are bundled with yt
+and are developed by 3rd party upstream.
+"""

diff -r ee60b2894117d89ca0ba2a5b5dfa057df30d6166 -r e17e82bf3222ba96d300b78c6f1ed313e58656ce yt/extern/parameterized.py
--- /dev/null
+++ b/yt/extern/parameterized.py
@@ -0,0 +1,226 @@
+import re
+import inspect
+from functools import wraps
+from collections import namedtuple
+
+from nose.tools import nottest
+from unittest import TestCase
+
+from . import six
+
+if six.PY3:
+    def new_instancemethod(f, *args):
+        return f
+else:
+    import new
+    new_instancemethod = new.instancemethod
+
+_param = namedtuple("param", "args kwargs")
+
+class param(_param):
+    """ Represents a single parameter to a test case.
+
+        For example::
+
+            >>> p = param("foo", bar=16)
+            >>> p
+            param("foo", bar=16)
+            >>> p.args
+            ('foo', )
+            >>> p.kwargs
+            {'bar': 16}
+
+        Intended to be used as an argument to ``@parameterized``::
+
+            @parameterized([
+                param("foo", bar=16),
+            ])
+            def test_stuff(foo, bar=16):
+                pass
+        """
+
+    def __new__(cls, *args , **kwargs):
+        return _param.__new__(cls, args, kwargs)
+
+    @classmethod
+    def explicit(cls, args=None, kwargs=None):
+        """ Creates a ``param`` by explicitly specifying ``args`` and
+            ``kwargs``::
+
+                >>> param.explicit([1,2,3])
+                param(*(1, 2, 3))
+                >>> param.explicit(kwargs={"foo": 42})
+                param(*(), **{"foo": "42"})
+            """
+        args = args or ()
+        kwargs = kwargs or {}
+        return cls(*args, **kwargs)
+
+    @classmethod
+    def from_decorator(cls, args):
+        """ Returns an instance of ``param()`` for ``@parameterized`` argument
+            ``args``::
+
+                >>> param.from_decorator((42, ))
+                param(args=(42, ), kwargs={})
+                >>> param.from_decorator("foo")
+                param(args=("foo", ), kwargs={})
+            """
+        if isinstance(args, param):
+            return args
+        if isinstance(args, six.string_types):
+            args = (args, )
+        return cls(*args)
+
+    def __repr__(self):
+        return "param(*%r, **%r)" %self
+
+class parameterized(object):
+    """ Parameterize a test case::
+
+            class TestInt(object):
+                @parameterized([
+                    ("A", 10),
+                    ("F", 15),
+                    param("10", 42, base=42)
+                ])
+                def test_int(self, input, expected, base=16):
+                    actual = int(input, base=base)
+                    assert_equal(actual, expected)
+
+            @parameterized([
+                (2, 3, 5)
+                (3, 5, 8),
+            ])
+            def test_add(a, b, expected):
+                assert_equal(a + b, expected)
+        """
+
+    def __init__(self, input):
+        self.get_input = self.input_as_callable(input)
+
+    def __call__(self, test_func):
+        self.assert_not_in_testcase_subclass()
+
+        @wraps(test_func)
+        def parameterized_helper_method(test_self=None):
+            f = test_func
+            if test_self is not None:
+                # If we are a test method (which we suppose to be true if we
+                # are being passed a "self" argument), we first need to create
+                # an instance method, attach it to the instance of the test
+                # class, then pull it back off to turn it into a bound method.
+                # If we don't do this, Nose gets cranky.
+                f = self.make_bound_method(test_self, test_func)
+            # Note: because nose is so very picky, the more obvious
+            # ``return self.yield_nose_tuples(f)`` won't work here.
+            for nose_tuple in self.yield_nose_tuples(f):
+                yield nose_tuple
+
+        test_func.__name__ = "_helper_for_%s" %(test_func.__name__, )
+        parameterized_helper_method.parameterized_input = input
+        parameterized_helper_method.parameterized_func = test_func
+        return parameterized_helper_method
+
+    def yield_nose_tuples(self, func):
+        for args in self.get_input():
+            p = param.from_decorator(args)
+            # ... then yield that as a tuple. If those steps aren't
+            # followed precicely, Nose gets upset and doesn't run the test
+            # or doesn't run setup methods.
+            yield self.param_as_nose_tuple(p, func)
+
+    def param_as_nose_tuple(self, p, func):
+        nose_func = func
+        nose_args = p.args
+        if p.kwargs:
+            nose_func = wraps(func)(lambda args, kwargs: func(*args, **kwargs))
+            nose_args = (p.args, p.kwargs)
+        return (nose_func, ) + nose_args
+
+    def make_bound_method(self, instance, func):
+        cls = type(instance)
+        im_f = new_instancemethod(func, None, cls)
+        setattr(cls, func.__name__, im_f)
+        return getattr(instance, func.__name__)
+
+    def assert_not_in_testcase_subclass(self):
+        parent_classes = self._terrible_magic_get_defining_classes()
+        if any(issubclass(cls, TestCase) for cls in parent_classes):
+            raise Exception("Warning: '@parameterized' tests won't work "
+                            "inside subclasses of 'TestCase' - use "
+                            "'@parameterized.expand' instead")
+
+    def _terrible_magic_get_defining_classes(self):
+        """ Returns the set of parent classes of the class currently being defined.
+            Will likely only work if called from the ``parameterized`` decorator.
+            This function is entirely @brandon_rhodes's fault, as he suggested
+            the implementation: http://stackoverflow.com/a/8793684/71522
+            """
+        stack = inspect.stack()
+        if len(stack) <= 4:
+            return []
+        frame = stack[4]
+        code_context = frame[4] and frame[4][0].strip()
+        if not (code_context and code_context.startswith("class ")):
+            return []
+        _, parents = code_context.split("(", 1)
+        parents, _ = parents.rsplit(")", 1)
+        return eval("[" + parents + "]", frame[0].f_globals, frame[0].f_locals)
+
+    @classmethod
+    def input_as_callable(cls, input):
+        if callable(input):
+            return lambda: cls.check_input_values(input())
+        input_values = cls.check_input_values(input)
+        return lambda: input_values
+
+    @classmethod
+    def check_input_values(cls, input_values):
+        if not hasattr(input_values, "__iter__"):
+            raise ValueError("expected iterable input; got %r" %(input, ))
+        return input_values
+
+    @classmethod
+    def expand(cls, input):
+        """ A "brute force" method of parameterizing test cases. Creates new
+            test cases and injects them into the namespace that the wrapped
+            function is being defined in. Useful for parameterizing tests in
+            subclasses of 'UnitTest', where Nose test generators don't work.
+
+            >>> @parameterized.expand([("foo", 1, 2)])
+            ... def test_add1(name, input, expected):
+            ...     actual = add1(input)
+            ...     assert_equal(actual, expected)
+            ...
+            >>> locals()
+            ... 'test_add1_foo_0': <function ...> ...
+            >>>
+            """
+
+        def parameterized_expand_wrapper(f):
+            stack = inspect.stack()
+            frame = stack[1]
+            frame_locals = frame[0].f_locals
+
+            base_name = f.__name__
+            get_input = cls.input_as_callable(input)
+            for num, args in enumerate(get_input()):
+                p = param.from_decorator(args)
+                name_suffix = "_%s" %(num, )
+                if len(p.args) > 0 and isinstance(p.args[0], six.string_types):
+                    name_suffix += "_" + cls.to_safe_name(p.args[0])
+                name = base_name + name_suffix
+                frame_locals[name] = cls.param_as_standalone_func(p, f, name)
+            return nottest(f)
+        return parameterized_expand_wrapper
+
+    @classmethod
+    def param_as_standalone_func(cls, p, func, name):
+        standalone_func = lambda *a: func(*(a + p.args), **p.kwargs)
+        standalone_func.__name__ = name
+        return standalone_func
+
+    @classmethod
+    def to_safe_name(cls, s):
+        return str(re.sub("[^a-zA-Z0-9_]", "", s))

diff -r ee60b2894117d89ca0ba2a5b5dfa057df30d6166 -r e17e82bf3222ba96d300b78c6f1ed313e58656ce yt/extern/six.py
--- /dev/null
+++ b/yt/extern/six.py
@@ -0,0 +1,404 @@
+"""Utilities for writing code that runs on Python 2 and 3"""
+
+# Copyright (c) 2010-2013 Benjamin Peterson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import operator
+import sys
+import types
+
+__author__ = "Benjamin Peterson <benjamin at python.org>"
+__version__ = "1.3.0"
+
+
+# True if we are running on Python 3.
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    string_types = str,
+    integer_types = int,
+    class_types = type,
+    text_type = str
+    binary_type = bytes
+
+    MAXSIZE = sys.maxsize
+else:
+    string_types = basestring,
+    integer_types = (int, long)
+    class_types = (type, types.ClassType)
+    text_type = unicode
+    binary_type = str
+
+    if sys.platform.startswith("java"):
+        # Jython always uses 32 bits.
+        MAXSIZE = int((1 << 31) - 1)
+    else:
+        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
+        class X(object):
+            def __len__(self):
+                return 1 << 31
+        try:
+            len(X())
+        except OverflowError:
+            # 32-bit
+            MAXSIZE = int((1 << 31) - 1)
+        else:
+            # 64-bit
+            MAXSIZE = int((1 << 63) - 1)
+            del X
+
+
+def _add_doc(func, doc):
+    """Add documentation to a function."""
+    func.__doc__ = doc
+
+
+def _import_module(name):
+    """Import module, returning the module after the last dot."""
+    __import__(name)
+    return sys.modules[name]
+
+
+class _LazyDescr(object):
+
+    def __init__(self, name):
+        self.name = name
+
+    def __get__(self, obj, tp):
+        result = self._resolve()
+        setattr(obj, self.name, result)
+        # This is a bit ugly, but it avoids running this again.
+        delattr(tp, self.name)
+        return result
+
+
+class MovedModule(_LazyDescr):
+
+    def __init__(self, name, old, new=None):
+        super(MovedModule, self).__init__(name)
+        if PY3:
+            if new is None:
+                new = name
+            self.mod = new
+        else:
+            self.mod = old
+
+    def _resolve(self):
+        return _import_module(self.mod)
+
+
+class MovedAttribute(_LazyDescr):
+
+    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
+        super(MovedAttribute, self).__init__(name)
+        if PY3:
+            if new_mod is None:
+                new_mod = name
+            self.mod = new_mod
+            if new_attr is None:
+                if old_attr is None:
+                    new_attr = name
+                else:
+                    new_attr = old_attr
+            self.attr = new_attr
+        else:
+            self.mod = old_mod
+            if old_attr is None:
+                old_attr = name
+            self.attr = old_attr
+
+    def _resolve(self):
+        module = _import_module(self.mod)
+        return getattr(module, self.attr)
+
+
+
+class _MovedItems(types.ModuleType):
+    """Lazy loading of moved objects"""
+
+
+_moved_attributes = [
+    MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
+    MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
+    MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
+    MovedAttribute("map", "itertools", "builtins", "imap", "map"),
+    MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
+    MovedAttribute("reduce", "__builtin__", "functools"),
+    MovedAttribute("StringIO", "StringIO", "io"),
+    MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
+    MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
+
+    MovedModule("builtins", "__builtin__"),
+    MovedModule("configparser", "ConfigParser"),
+    MovedModule("copyreg", "copy_reg"),
+    MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
+    MovedModule("http_cookies", "Cookie", "http.cookies"),
+    MovedModule("html_entities", "htmlentitydefs", "html.entities"),
+    MovedModule("html_parser", "HTMLParser", "html.parser"),
+    MovedModule("http_client", "httplib", "http.client"),
+    MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+    MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
+    MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
+    MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
+    MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
+    MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
+    MovedModule("cPickle", "cPickle", "pickle"),
+    MovedModule("queue", "Queue"),
+    MovedModule("reprlib", "repr"),
+    MovedModule("socketserver", "SocketServer"),
+    MovedModule("tkinter", "Tkinter"),
+    MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
+    MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
+    MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
+    MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
+    MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
+    MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
+    MovedModule("tkinter_colorchooser", "tkColorChooser",
+                "tkinter.colorchooser"),
+    MovedModule("tkinter_commondialog", "tkCommonDialog",
+                "tkinter.commondialog"),
+    MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_font", "tkFont", "tkinter.font"),
+    MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
+    MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
+                "tkinter.simpledialog"),
+    MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
+    MovedModule("winreg", "_winreg"),
+]
+for attr in _moved_attributes:
+    setattr(_MovedItems, attr.name, attr)
+del attr
+
+moves = sys.modules[__name__ + ".moves"] = _MovedItems("moves")
+
+
+def add_move(move):
+    """Add an item to six.moves."""
+    setattr(_MovedItems, move.name, move)
+
+
+def remove_move(name):
+    """Remove item from six.moves."""
+    try:
+        delattr(_MovedItems, name)
+    except AttributeError:
+        try:
+            del moves.__dict__[name]
+        except KeyError:
+            raise AttributeError("no such move, %r" % (name,))
+
+
+if PY3:
+    _meth_func = "__func__"
+    _meth_self = "__self__"
+
+    _func_closure = "__closure__"
+    _func_code = "__code__"
+    _func_defaults = "__defaults__"
+    _func_globals = "__globals__"
+
+    _iterkeys = "keys"
+    _itervalues = "values"
+    _iteritems = "items"
+    _iterlists = "lists"
+else:
+    _meth_func = "im_func"
+    _meth_self = "im_self"
+
+    _func_closure = "func_closure"
+    _func_code = "func_code"
+    _func_defaults = "func_defaults"
+    _func_globals = "func_globals"
+
+    _iterkeys = "iterkeys"
+    _itervalues = "itervalues"
+    _iteritems = "iteritems"
+    _iterlists = "iterlists"
+
+
+try:
+    advance_iterator = next
+except NameError:
+    def advance_iterator(it):
+        return it.next()
+next = advance_iterator
+
+
+try:
+    callable = callable
+except NameError:
+    def callable(obj):
+        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
+
+
+if PY3:
+    def get_unbound_function(unbound):
+        return unbound
+
+    Iterator = object
+else:
+    def get_unbound_function(unbound):
+        return unbound.im_func
+
+    class Iterator(object):
+
+        def next(self):
+            return type(self).__next__(self)
+
+    callable = callable
+_add_doc(get_unbound_function,
+         """Get the function out of a possibly unbound function""")
+
+
+get_method_function = operator.attrgetter(_meth_func)
+get_method_self = operator.attrgetter(_meth_self)
+get_function_closure = operator.attrgetter(_func_closure)
+get_function_code = operator.attrgetter(_func_code)
+get_function_defaults = operator.attrgetter(_func_defaults)
+get_function_globals = operator.attrgetter(_func_globals)
+
+
+def iterkeys(d, **kw):
+    """Return an iterator over the keys of a dictionary."""
+    return iter(getattr(d, _iterkeys)(**kw))
+
+def itervalues(d, **kw):
+    """Return an iterator over the values of a dictionary."""
+    return iter(getattr(d, _itervalues)(**kw))
+
+def iteritems(d, **kw):
+    """Return an iterator over the (key, value) pairs of a dictionary."""
+    return iter(getattr(d, _iteritems)(**kw))
+
+def iterlists(d, **kw):
+    """Return an iterator over the (key, [values]) pairs of a dictionary."""
+    return iter(getattr(d, _iterlists)(**kw))
+
+
+if PY3:
+    def b(s):
+        return s.encode("latin-1")
+    def u(s):
+        return s
+    if sys.version_info[1] <= 1:
+        def int2byte(i):
+            return bytes((i,))
+    else:
+        # This is about 2x faster than the implementation above on 3.2+
+        int2byte = operator.methodcaller("to_bytes", 1, "big")
+    import io
+    StringIO = io.StringIO
+    BytesIO = io.BytesIO
+else:
+    def b(s):
+        return s
+    def u(s):
+        return unicode(s, "unicode_escape")
+    int2byte = chr
+    import StringIO
+    StringIO = BytesIO = StringIO.StringIO
+_add_doc(b, """Byte literal""")
+_add_doc(u, """Text literal""")
+
+
+if PY3:
+    import builtins
+    exec_ = getattr(builtins, "exec")
+
+
+    def reraise(tp, value, tb=None):
+        if value.__traceback__ is not tb:
+            raise value.with_traceback(tb)
+        raise value
+
+
+    print_ = getattr(builtins, "print")
+    del builtins
+
+else:
+    def exec_(_code_, _globs_=None, _locs_=None):
+        """Execute code in a namespace."""
+        if _globs_ is None:
+            frame = sys._getframe(1)
+            _globs_ = frame.f_globals
+            if _locs_ is None:
+                _locs_ = frame.f_locals
+            del frame
+        elif _locs_ is None:
+            _locs_ = _globs_
+        exec("""exec _code_ in _globs_, _locs_""")
+
+
+    exec_("""def reraise(tp, value, tb=None):
+    raise tp, value, tb
+""")
+
+
+    def print_(*args, **kwargs):
+        """The new-style print function."""
+        fp = kwargs.pop("file", sys.stdout)
+        if fp is None:
+            return
+        def write(data):
+            if not isinstance(data, basestring):
+                data = str(data)
+            fp.write(data)
+        want_unicode = False
+        sep = kwargs.pop("sep", None)
+        if sep is not None:
+            if isinstance(sep, unicode):
+                want_unicode = True
+            elif not isinstance(sep, str):
+                raise TypeError("sep must be None or a string")
+        end = kwargs.pop("end", None)
+        if end is not None:
+            if isinstance(end, unicode):
+                want_unicode = True
+            elif not isinstance(end, str):
+                raise TypeError("end must be None or a string")
+        if kwargs:
+            raise TypeError("invalid keyword arguments to print()")
+        if not want_unicode:
+            for arg in args:
+                if isinstance(arg, unicode):
+                    want_unicode = True
+                    break
+        if want_unicode:
+            newline = unicode("\n")
+            space = unicode(" ")
+        else:
+            newline = "\n"
+            space = " "
+        if sep is None:
+            sep = space
+        if end is None:
+            end = newline
+        for i, arg in enumerate(args):
+            if i:
+                write(sep)
+            write(arg)
+        write(end)
+
+_add_doc(reraise, """Reraise an exception.""")
+
+
+def with_metaclass(meta, base=object):
+    """Create a base class with a metaclass."""
+    return meta("NewBase", (base,), {})

diff -r ee60b2894117d89ca0ba2a5b5dfa057df30d6166 -r e17e82bf3222ba96d300b78c6f1ed313e58656ce yt/setup.py
--- a/yt/setup.py
+++ b/yt/setup.py
@@ -9,6 +9,7 @@
     config = Configuration('yt', parent_package, top_path)
     config.add_subpackage('analysis_modules')
     config.add_subpackage('data_objects')
+    config.add_subpackage('extern')
     config.add_subpackage('frontends')
     config.add_subpackage('gui')
     config.add_subpackage('utilities')


https://bitbucket.org/yt_analysis/yt-3.0/commits/488e933730ca/
Changeset:   488e933730ca
Branch:      yt
User:        xarthisius
Date:        2013-08-19 19:38:35
Summary:     Use mkstemp() for saving files in PlotWindowAttributeTest. Fixes #628
Affected #:  1 file

diff -r e17e82bf3222ba96d300b78c6f1ed313e58656ce -r 488e933730cabb86bc2a726fdd05599149c6621b yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -33,6 +33,7 @@
 import cPickle
 import shelve
 import zlib
+import tempfile
 
 from matplotlib.testing.compare import compare_images
 from nose.plugins import Plugin
@@ -604,9 +605,11 @@
                                 self.plot_axis, self.plot_kwargs)
         attr = getattr(plot, self.attr_name)
         attr(*self.attr_args[0], **self.attr_args[1])
-        fn = plot.save()[0]
-        image = mpimg.imread(fn)
-        os.remove(fn)
+        tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+        os.close(tmpfd)
+        plot.save(name=tmpname)
+        image = mpimg.imread(tmpname)
+        os.remove(tmpname)
         return [zlib.compress(image.dumps())]
 
     def compare(self, new_result, old_result):


https://bitbucket.org/yt_analysis/yt-3.0/commits/28ea42cfdb90/
Changeset:   28ea42cfdb90
Branch:      yt
User:        xarthisius
Date:        2013-08-19 19:39:58
Summary:     Rewrite test_plotwindow using nose-parameterized
Affected #:  1 file

diff -r 488e933730cabb86bc2a726fdd05599149c6621b -r 28ea42cfdb90c6871da88b9ac598b9e4d0ff1b18 yt/visualization/tests/test_plotwindow.py
--- a/yt/visualization/tests/test_plotwindow.py
+++ b/yt/visualization/tests/test_plotwindow.py
@@ -22,9 +22,12 @@
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
+import itertools
 import os
 import tempfile
 import shutil
+import unittest
+from yt.extern.parameterized import parameterized, param
 from yt.testing import \
     fake_random_pf, assert_equal, assert_rel_equal
 from yt.utilities.answer_testing.framework import \
@@ -65,132 +68,165 @@
 
     return image_type == os.path.splitext(fname)[1]
 
-attr_args ={ "pan"             : [( ((0.1, 0.1),), {} )],
-             "pan_rel"         : [( ((0.1, 0.1),), {} )],
-             "set_axes_unit"   : [( ("kpc",), {} ),
-                                  ( ("Mpc",), {} ),
-                                  ( (("kpc", "kpc"),), {} ),
-                                  ( (("kpc", "Mpc"),), {} )],
-             "set_buff_size"   : [( (1600,), {} ),
-                                  ( ((600, 800),), {} )],
-             "set_center"      : [( ((0.4, 0.3),), {} )],
-             "set_cmap"        : [( ('Density', 'RdBu'), {} ),
-                                  ( ('Density', 'kamae'), {} )],
-             "set_font"        : [( ({'family':'sans-serif', 'style':'italic',
-                                      'weight':'bold', 'size':24},), {} )],
-             "set_log"         : [( ('Density', False), {} )],
-             "set_window_size" : [( (7.0,), {} )],
-             "set_zlim" : [( ('Density', 1e-25, 1e-23), {} ),
-                           ( ('Density', 1e-25, None), {'dynamic_range' : 4} )],
-             "zoom" : [( (10,), {} )] }
 
-m7 = "DD0010/moving7_0010"
-wt = "WindTunnel/windtunnel_4lev_hdf5_plt_cnt_0030"
- at requires_pf(m7)
- at requires_pf(wt)
+TEST_FLNMS = [None, 'test.png', 'test.eps',
+              'test.ps', 'test.pdf']
+M7 = "DD0010/moving7_0010"
+WT = "WindTunnel/windtunnel_4lev_hdf5_plt_cnt_0030"
+
+ATTR_ARGS = {"pan": [(((0.1, 0.1), ), {})],
+             "pan_rel": [(((0.1, 0.1), ), {})],
+             "set_axes_unit": [(("kpc", ), {}),
+                               (("Mpc", ), {}),
+                               ((("kpc", "kpc"),), {}),
+                               ((("kpc", "Mpc"),), {})],
+             "set_buff_size": [((1600, ), {}),
+                               (((600, 800), ), {})],
+             "set_center": [(((0.4, 0.3), ), {})],
+             "set_cmap": [(('Density', 'RdBu'), {}),
+                          (('Density', 'kamae'), {})],
+             "set_font": [(({'family': 'sans-serif', 'style': 'italic',
+                             'weight': 'bold', 'size': 24}, ), {})],
+             "set_log": [(('Density', False), {})],
+             "set_window_size": [((7.0, ), {})],
+             "set_zlim": [(('Density', 1e-25, 1e-23), {}),
+                          (('Density', 1e-25, None), {'dynamic_range': 4})],
+             "zoom": [((10, ), {})]}
+
+
+ at requires_pf(M7)
 def test_attributes():
     """Test plot member functions that aren't callbacks"""
     plot_field = 'Density'
     decimals = 3
 
-    pf = data_dir_load(m7)
+    pf = data_dir_load(M7)
     for ax in 'xyz':
-        for attr_name in attr_args.keys():
-            for args in attr_args[attr_name]:
+        for attr_name in ATTR_ARGS.keys():
+            for args in ATTR_ARGS[attr_name]:
                 yield PlotWindowAttributeTest(pf, plot_field, ax, attr_name,
                                               args, decimals)
-    pf = data_dir_load(wt)
+
+
+ at requires_pf(WT)
+def test_attributes_wt():
+    plot_field = 'Density'
+    decimals = 3
+
+    pf = data_dir_load(WT)
     ax = 'z'
-    for attr_name in attr_args.keys():
-        for args in attr_args[attr_name]:
+    for attr_name in ATTR_ARGS.keys():
+        for args in ATTR_ARGS[attr_name]:
             yield PlotWindowAttributeTest(pf, plot_field, ax, attr_name,
                                           args, decimals)
 
-def test_setwidth():
-    pf = fake_random_pf(64)
 
-    slc = SlicePlot(pf, 0, 'Density')
+class TestSetWidth(unittest.TestCase):
 
-    yield assert_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(0.0, 1.0), (0.0, 1.0), (1.0, 1.0)]
+    pf = None
 
-    slc.set_width((0.5,0.8))
+    def setUp(self):
+        if self.pf is None:
+            self.pf = fake_random_pf(64)
+            self.slc = SlicePlot(self.pf, 0, 'Density')
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(0.25, 0.75), (0.1, 0.9), (0.5, 0.8)], 15
+    def _assert_15kpc(self):
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (15.0 / self.pf['kpc'], 15. / self.pf['kpc'])], 15)
 
-    slc.set_width(15,'kpc')
+    def _assert_15_10kpc(self):
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (-5.0 / self.pf['kpc'], 5.0 / self.pf['kpc']),
+                          (15.0 / self.pf['kpc'], 10. / self.pf['kpc'])], 15)
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (15/pf['kpc'], 15/pf['kpc'])], 15
+    def test_set_width_one(self):
+        assert_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                     [(0.0, 1.0), (0.0, 1.0), (1.0, 1.0)])
 
-    slc.set_width((15,'kpc'))
+    def test_set_width_nonequal(self):
+        self.slc.set_width((0.5, 0.8))
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(0.25, 0.75), (0.1, 0.9), (0.5, 0.8)], 15)
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (15/pf['kpc'], 15/pf['kpc'])], 15
+    def test_twoargs_eq(self):
+        self.slc.set_width(15, 'kpc')
+        self._assert_15kpc()
 
-    slc.set_width(((15,'kpc'),(10,'kpc')))
+    def test_tuple_eq(self):
+        self.slc.set_width((15, 'kpc'))
+        self._assert_15kpc()
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+    def test_tuple_of_tuples_neq(self):
+        self.slc.set_width(((15, 'kpc'), (10, 'kpc')))
+        self._assert_15_10kpc()
 
-    slc.set_width(((15,'kpc'),(10000,'pc')))
+    def test_tuple_of_tuples_neq2(self):
+        self.slc.set_width(((15, 'kpc'), (10000, 'pc')))
+        self._assert_15_10kpc()
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+    def test_pair_of_tuples_neq(self):
+        self.slc.set_width((15, 'kpc'), (10000, 'pc'))
+        self._assert_15_10kpc()
 
-    slc.set_width((15,'kpc'),(10000,'pc'))
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+class TestPlotWindowSave(unittest.TestCase):
 
-def test_save():
-    """Test plot window creation and saving to disk."""
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+    @classmethod
+    def setUpClass(cls):
+        test_pf = fake_random_pf(64)
+        normal = [1, 1, 1]
+        ds_region = test_pf.h.region([0.5] * 3, [0.4] * 3, [0.6] * 3)
+        slices = [SlicePlot(test_pf, dim, 'Density') for dim in range(3)]
+        projections = []
+        projections_ds = []
+        for dim in range(3):
+            projections.append(ProjectionPlot(test_pf, dim, 'Density'))
+            projections_ds.append(ProjectionPlot(test_pf, dim, 'Density',
+                                                 data_source=ds_region))
+        cls.pf = test_pf
+        cls.normal = normal
+        cls.slices = slices
+        cls.projections = projections
+        cls.projections_ds = projections_ds
 
-    normal = [1, 1, 1]
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp()
+        self.curdir = os.getcwd()
+        os.chdir(self.tmpdir)
 
-    test_pf = fake_random_pf(64)
-    test_flnms = [None, 'test.png', 'test.eps',
-                  'test.ps', 'test.pdf']
+    def tearDown(self):
+        os.chdir(self.curdir)
+        shutil.rmtree(self.tmpdir)
 
-    ds_region = test_pf.h.region([0.5]*3,[0.4]*3,[0.6]*3)
+    @parameterized.expand(
+        param.explicit(item)
+        for item in itertools.product(range(3), TEST_FLNMS))
+    def test_slice_plot(self, dim, fname):
+        assert assert_fname(self.slices[dim].save(fname)[0])
 
-    for dim in [0, 1, 2]:
-        obj = SlicePlot(test_pf, dim, 'Density')
-        for fname in test_flnms:
-            yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand(
+        param.explicit(item)
+        for item in itertools.product(range(3), TEST_FLNMS))
+    def test_projection_plot(self, dim, fname):
+        assert assert_fname(self.projections[dim].save(fname)[0])
 
-    for dim in [0, 1, 2]:
-        obj = ProjectionPlot(test_pf, dim, 'Density')
-        for fname in test_flnms:
-            yield assert_equal, assert_fname(obj.save(fname)[0]), True
-        # Test ProjectionPlot's data_source keyword
-        obj = ProjectionPlot(test_pf, dim, 'Density',
-                             data_source=ds_region)
-        obj.save()
+    @parameterized.expand([(0, ), (1, ), (2, )])
+    def test_projection_plot_ds(self, dim):
+        self.projections_ds[dim].save()
 
-    obj = OffAxisSlicePlot(test_pf, normal, 'Density')
-    for fname in test_flnms:
-        yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand(
+        param.explicit((fname, ))
+        for fname in TEST_FLNMS)
+    def test_offaxis_slice_plot(self, fname):
+        obj = OffAxisSlicePlot(self.pf, self.normal, 'Density')
+        assert assert_fname(obj.save(fname)[0])
 
-    obj = OffAxisProjectionPlot(test_pf, normal, 'Density')
-    for fname in test_flnms:
-        yield assert_equal, assert_fname(obj.save(fname)[0]), True
-
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
+    @parameterized.expand(
+        param.explicit((fname, ))
+        for fname in TEST_FLNMS)
+    def test_offaxis_projection_plot(self, fname):
+        obj = OffAxisProjectionPlot(self.pf, self.normal, 'Density')
+        assert assert_fname(obj.save(fname)[0])


https://bitbucket.org/yt_analysis/yt-3.0/commits/5733aae41d94/
Changeset:   5733aae41d94
Branch:      yt
User:        xarthisius
Date:        2013-08-19 19:46:09
Summary:     Initialize OffAxisSlice/Projection only once in tests
Affected #:  1 file

diff -r 28ea42cfdb90c6871da88b9ac598b9e4d0ff1b18 -r 5733aae41d94abffef18b105cc8561f714f25802 yt/visualization/tests/test_plotwindow.py
--- a/yt/visualization/tests/test_plotwindow.py
+++ b/yt/visualization/tests/test_plotwindow.py
@@ -179,18 +179,18 @@
         test_pf = fake_random_pf(64)
         normal = [1, 1, 1]
         ds_region = test_pf.h.region([0.5] * 3, [0.4] * 3, [0.6] * 3)
-        slices = [SlicePlot(test_pf, dim, 'Density') for dim in range(3)]
         projections = []
         projections_ds = []
         for dim in range(3):
             projections.append(ProjectionPlot(test_pf, dim, 'Density'))
             projections_ds.append(ProjectionPlot(test_pf, dim, 'Density',
                                                  data_source=ds_region))
-        cls.pf = test_pf
-        cls.normal = normal
-        cls.slices = slices
+
+        cls.slices = [SlicePlot(test_pf, dim, 'Density') for dim in range(3)]
         cls.projections = projections
         cls.projections_ds = projections_ds
+        cls.offaxis_slice = OffAxisSlicePlot(test_pf, normal, 'Density')
+        cls.offaxis_proj = OffAxisProjectionPlot(test_pf, normal, 'Density')
 
     def setUp(self):
         self.tmpdir = tempfile.mkdtemp()
@@ -221,12 +221,10 @@
         param.explicit((fname, ))
         for fname in TEST_FLNMS)
     def test_offaxis_slice_plot(self, fname):
-        obj = OffAxisSlicePlot(self.pf, self.normal, 'Density')
-        assert assert_fname(obj.save(fname)[0])
+        assert assert_fname(self.offaxis_slice.save(fname)[0])
 
     @parameterized.expand(
         param.explicit((fname, ))
         for fname in TEST_FLNMS)
     def test_offaxis_projection_plot(self, fname):
-        obj = OffAxisProjectionPlot(self.pf, self.normal, 'Density')
-        assert assert_fname(obj.save(fname)[0])
+        assert assert_fname(self.offaxis_proj.save(fname)[0])


https://bitbucket.org/yt_analysis/yt-3.0/commits/5f1eb559335b/
Changeset:   5f1eb559335b
Branch:      yt
User:        xarthisius
Date:        2013-08-19 20:05:02
Summary:     Use mkstemp() for saving files in test_projection. Fixes #628
Affected #:  1 file

diff -r 5733aae41d94abffef18b105cc8561f714f25802 -r 5f1eb559335bda89a4d168b656043e192d685156 yt/data_objects/tests/test_projection.py
--- a/yt/data_objects/tests/test_projection.py
+++ b/yt/data_objects/tests/test_projection.py
@@ -37,7 +37,9 @@
                 yield assert_equal, np.unique(proj["pdx"]), 1.0/(dims[xax]*2.0)
                 yield assert_equal, np.unique(proj["pdy"]), 1.0/(dims[yax]*2.0)
                 pw = proj.to_pw()
-                fns += pw.save()
+                tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+                os.close(tmpfd)
+                fns += pw.save(name=tmpname)
                 frb = proj.to_frb((1.0,'unitary'), 64)
                 for proj_field in ['Ones', 'Density']:
                     yield assert_equal, frb[proj_field].info['data_source'], \


https://bitbucket.org/yt_analysis/yt-3.0/commits/90427578b989/
Changeset:   90427578b989
Branch:      yt
User:        xarthisius
Date:        2013-08-19 20:53:43
Summary:     Use mkstemp() for saving files in remaining tests. Finally fixes #628
Affected #:  2 files

diff -r 5f1eb559335bda89a4d168b656043e192d685156 -r 90427578b9893d1ad578abad0a3c945e9937f114 yt/data_objects/tests/test_cutting_plane.py
--- a/yt/data_objects/tests/test_cutting_plane.py
+++ b/yt/data_objects/tests/test_cutting_plane.py
@@ -1,5 +1,6 @@
 from yt.testing import *
 import os
+import tempfile
 
 def setup():
     from yt.config import ytcfg
@@ -23,7 +24,9 @@
         yield assert_equal, cut["Ones"].min(), 1.0
         yield assert_equal, cut["Ones"].max(), 1.0
         pw = cut.to_pw()
-        fns += pw.save()
+        tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+        os.close(tmpfd)
+        fns += pw.save(name=tmpname)
         frb = cut.to_frb((1.0,'unitary'), 64)
         for cut_field in ['Ones', 'Density']:
             yield assert_equal, frb[cut_field].info['data_source'], \

diff -r 5f1eb559335bda89a4d168b656043e192d685156 -r 90427578b9893d1ad578abad0a3c945e9937f114 yt/data_objects/tests/test_slice.py
--- a/yt/data_objects/tests/test_slice.py
+++ b/yt/data_objects/tests/test_slice.py
@@ -72,7 +72,9 @@
                 yield assert_equal, np.unique(slc["pdx"]), 0.5 / dims[xax]
                 yield assert_equal, np.unique(slc["pdy"]), 0.5 / dims[yax]
                 pw = slc.to_pw()
-                fns += pw.save()
+                tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+                os.close(tmpfd)
+                fns += pw.save(name=tmpname)
                 frb = slc.to_frb((1.0, 'unitary'), 64)
                 for slc_field in ['Ones', 'Density']:
                     yield assert_equal, frb[slc_field].info['data_source'], \


https://bitbucket.org/yt_analysis/yt-3.0/commits/a155cec8f2c5/
Changeset:   a155cec8f2c5
Branch:      yt
User:        xarthisius
Date:        2013-08-19 21:56:36
Summary:     Import missing tempfile, move os.remove into try/except clause
Affected #:  3 files

diff -r 90427578b9893d1ad578abad0a3c945e9937f114 -r a155cec8f2c51ba9a9eb1494ce2047d5d553898b yt/data_objects/tests/test_cutting_plane.py
--- a/yt/data_objects/tests/test_cutting_plane.py
+++ b/yt/data_objects/tests/test_cutting_plane.py
@@ -8,7 +8,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 def test_cutting_plane():
     for nprocs in [8, 1]:

diff -r 90427578b9893d1ad578abad0a3c945e9937f114 -r a155cec8f2c51ba9a9eb1494ce2047d5d553898b yt/data_objects/tests/test_projection.py
--- a/yt/data_objects/tests/test_projection.py
+++ b/yt/data_objects/tests/test_projection.py
@@ -1,5 +1,6 @@
 from yt.testing import *
 import os
+import tempfile
 
 def setup():
     from yt.config import ytcfg
@@ -7,7 +8,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 def test_projection():
     for nprocs in [8, 1]:

diff -r 90427578b9893d1ad578abad0a3c945e9937f114 -r a155cec8f2c51ba9a9eb1494ce2047d5d553898b yt/data_objects/tests/test_slice.py
--- a/yt/data_objects/tests/test_slice.py
+++ b/yt/data_objects/tests/test_slice.py
@@ -42,7 +42,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 
 def test_slice():


https://bitbucket.org/yt_analysis/yt-3.0/commits/022e87daa5e4/
Changeset:   022e87daa5e4
Branch:      yt
User:        xarthisius
Date:        2013-08-19 22:19:56
Summary:     Add another missing import tempfile
Affected #:  1 file

diff -r a155cec8f2c51ba9a9eb1494ce2047d5d553898b -r 022e87daa5e4d0678406d06c09e3665f496a0580 yt/data_objects/tests/test_slice.py
--- a/yt/data_objects/tests/test_slice.py
+++ b/yt/data_objects/tests/test_slice.py
@@ -27,6 +27,7 @@
 """
 import os
 import numpy as np
+import tempfile
 from nose.tools import raises
 from yt.testing import \
     fake_random_pf, assert_equal, assert_array_equal


https://bitbucket.org/yt_analysis/yt-3.0/commits/7e42ac327db5/
Changeset:   7e42ac327db5
Branch:      yt
User:        MatthewTurk
Date:        2013-08-21 16:31:16
Summary:     Merged in xarthisius/yt (pull request #576)

Prevent tests from writting in the main yt dir
Affected #:  12 files

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/data_objects/tests/test_cutting_plane.py
--- a/yt/data_objects/tests/test_cutting_plane.py
+++ b/yt/data_objects/tests/test_cutting_plane.py
@@ -1,5 +1,6 @@
 from yt.testing import *
 import os
+import tempfile
 
 def setup():
     from yt.config import ytcfg
@@ -7,7 +8,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 def test_cutting_plane():
     for nprocs in [8, 1]:
@@ -23,7 +27,9 @@
         yield assert_equal, cut["Ones"].min(), 1.0
         yield assert_equal, cut["Ones"].max(), 1.0
         pw = cut.to_pw()
-        fns += pw.save()
+        tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+        os.close(tmpfd)
+        fns += pw.save(name=tmpname)
         frb = cut.to_frb((1.0,'unitary'), 64)
         for cut_field in ['Ones', 'Density']:
             yield assert_equal, frb[cut_field].info['data_source'], \

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/data_objects/tests/test_image_array.py
--- a/yt/data_objects/tests/test_image_array.py
+++ b/yt/data_objects/tests/test_image_array.py
@@ -1,130 +1,94 @@
-from yt.testing import *
-from yt.data_objects.image_array import ImageArray
 import numpy as np
 import os
 import tempfile
 import shutil
+import unittest
+from yt.data_objects.image_array import ImageArray
+from yt.testing import \
+    assert_equal
+
 
 def setup():
     from yt.config import ytcfg
-    ytcfg["yt","__withintesting"] = "True"
-    np.seterr(all = 'ignore')
+    ytcfg["yt", "__withintesting"] = "True"
+    np.seterr(all='ignore')
+
+
+def dummy_image(kstep, nlayers):
+    im = np.zeros([64, 128, nlayers])
+    for i in xrange(im.shape[0]):
+        for k in xrange(im.shape[2]):
+            im[i, :, k] = np.linspace(0.0, kstep * k, im.shape[1])
+    return im
+
 
 def test_rgba_rescale():
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-    im_arr = ImageArray(im)
+    im_arr = ImageArray(dummy_image(10.0, 4))
 
     new_im = im_arr.rescale(inline=False)
-    yield assert_equal, im_arr[:,:,:3].max(), 2*10.
-    yield assert_equal, im_arr[:,:,3].max(), 3*10.
-    yield assert_equal, new_im[:,:,:3].sum(axis=2).max(), 1.0 
-    yield assert_equal, new_im[:,:,3].max(), 1.0
+    yield assert_equal, im_arr[:, :, :3].max(), 2 * 10.
+    yield assert_equal, im_arr[:, :, 3].max(), 3 * 10.
+    yield assert_equal, new_im[:, :, :3].sum(axis=2).max(), 1.0
+    yield assert_equal, new_im[:, :, 3].max(), 1.0
 
     im_arr.rescale()
-    yield assert_equal, im_arr[:,:,:3].sum(axis=2).max(), 1.0
-    yield assert_equal, im_arr[:,:,3].max(), 1.0
+    yield assert_equal, im_arr[:, :, :3].sum(axis=2).max(), 1.0
+    yield assert_equal, im_arr[:, :, 3].max(), 1.0
 
-def test_image_array_hdf5():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
 
-    im = np.zeros([64,128,3])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,0.3*k, im.shape[1])
+class TestImageArray(unittest.TestCase):
 
-    myinfo = {'field':'dinosaurs', 'east_vector':np.array([1.,0.,0.]), 
-        'north_vector':np.array([0.,0.,1.]), 'normal_vector':np.array([0.,1.,0.]),  
-        'width':0.245, 'units':'cm', 'type':'rendering'}
+    tmpdir = None
+    curdir = None
 
-    im_arr = ImageArray(im, info=myinfo)
-    im_arr.save('test_3d_ImageArray')
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp()
+        self.curdir = os.getcwd()
+        os.chdir(self.tmpdir)
 
-    im = np.zeros([64,128])
-    for i in xrange(im.shape[0]):
-        im[i,:] = np.linspace(0.,0.3*k, im.shape[1])
+    def test_image_array_hdf5(self):
+        myinfo = {'field': 'dinosaurs', 'east_vector': np.array([1., 0., 0.]),
+                  'north_vector': np.array([0., 0., 1.]),
+                  'normal_vector': np.array([0., 1., 0.]),
+                  'width': 0.245, 'units': 'cm', 'type': 'rendering'}
 
-    myinfo = {'field':'dinosaurs', 'east_vector':np.array([1.,0.,0.]), 
-        'north_vector':np.array([0.,0.,1.]), 'normal_vector':np.array([0.,1.,0.]),  
-        'width':0.245, 'units':'cm', 'type':'rendering'}
+        im_arr = ImageArray(dummy_image(0.3, 3), info=myinfo)
+        im_arr.save('test_3d_ImageArray')
 
-    im_arr = ImageArray(im, info=myinfo)
-    im_arr.save('test_2d_ImageArray')
+        im = np.zeros([64, 128])
+        for i in xrange(im.shape[0]):
+            im[i, :] = np.linspace(0., 0.3 * 2, im.shape[1])
 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
+        myinfo = {'field': 'dinosaurs', 'east_vector': np.array([1., 0., 0.]),
+                  'north_vector': np.array([0., 0., 1.]),
+                  'normal_vector': np.array([0., 1., 0.]),
+                  'width': 0.245, 'units': 'cm', 'type': 'rendering'}
 
-def test_image_array_rgb_png():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+        im_arr = ImageArray(im, info=myinfo)
+        im_arr.save('test_2d_ImageArray')
 
-    im = np.zeros([64,128,3])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
+    def test_image_array_rgb_png(self):
+        im_arr = ImageArray(dummy_image(10.0, 3))
+        im_arr.write_png('standard.png')
 
-    im_arr = ImageArray(im)
-    im_arr.write_png('standard.png')
+    def test_image_array_rgba_png(self):
+        im_arr = ImageArray(dummy_image(10.0, 4))
+        im_arr.write_png('standard.png')
+        im_arr.write_png('non-scaled.png', rescale=False)
+        im_arr.write_png('black_bg.png', background='black')
+        im_arr.write_png('white_bg.png', background='white')
+        im_arr.write_png('green_bg.png', background=[0., 1., 0., 1.])
+        im_arr.write_png('transparent_bg.png', background=None)
 
-def test_image_array_rgba_png():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+    def test_image_array_background(self):
+        im_arr = ImageArray(dummy_image(10.0, 4))
+        im_arr.rescale()
+        new_im = im_arr.add_background_color([1., 0., 0., 1.], inline=False)
+        new_im.write_png('red_bg.png')
+        im_arr.add_background_color('black')
+        im_arr.write_png('black_bg2.png')
 
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-
-    im_arr = ImageArray(im)
-    im_arr.write_png('standard.png')
-    im_arr.write_png('non-scaled.png', rescale=False)
-    im_arr.write_png('black_bg.png', background='black')
-    im_arr.write_png('white_bg.png', background='white')
-    im_arr.write_png('green_bg.png', background=[0.,1.,0.,1.])
-    im_arr.write_png('transparent_bg.png', background=None)
-
-
-def test_image_array_background():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
-
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-
-    im_arr = ImageArray(im)
-    im_arr.rescale()
-    new_im = im_arr.add_background_color([1.,0.,0.,1.], inline=False)
-    new_im.write_png('red_bg.png')
-    im_arr.add_background_color('black')
-    im_arr.write_png('black_bg2.png')
- 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
-
-
-
-
-
-
-
-
-
-
-
-
-
+    def tearDown(self):
+        os.chdir(self.curdir)
+        # clean up
+        shutil.rmtree(self.tmpdir)

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/data_objects/tests/test_projection.py
--- a/yt/data_objects/tests/test_projection.py
+++ b/yt/data_objects/tests/test_projection.py
@@ -1,5 +1,6 @@
 from yt.testing import *
 import os
+import tempfile
 
 def setup():
     from yt.config import ytcfg
@@ -7,7 +8,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 def test_projection():
     for nprocs in [8, 1]:
@@ -37,7 +41,9 @@
                 yield assert_equal, np.unique(proj["pdx"]), 1.0/(dims[xax]*2.0)
                 yield assert_equal, np.unique(proj["pdy"]), 1.0/(dims[yax]*2.0)
                 pw = proj.to_pw()
-                fns += pw.save()
+                tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+                os.close(tmpfd)
+                fns += pw.save(name=tmpname)
                 frb = proj.to_frb((1.0,'unitary'), 64)
                 for proj_field in ['Ones', 'Density']:
                     yield assert_equal, frb[proj_field].info['data_source'], \

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/data_objects/tests/test_slice.py
--- a/yt/data_objects/tests/test_slice.py
+++ b/yt/data_objects/tests/test_slice.py
@@ -27,6 +27,7 @@
 """
 import os
 import numpy as np
+import tempfile
 from nose.tools import raises
 from yt.testing import \
     fake_random_pf, assert_equal, assert_array_equal
@@ -42,7 +43,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 
 def test_slice():
@@ -72,7 +76,9 @@
                 yield assert_equal, np.unique(slc["pdx"]), 0.5 / dims[xax]
                 yield assert_equal, np.unique(slc["pdy"]), 0.5 / dims[yax]
                 pw = slc.to_pw()
-                fns += pw.save()
+                tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+                os.close(tmpfd)
+                fns += pw.save(name=tmpname)
                 frb = slc.to_frb((1.0, 'unitary'), 64)
                 for slc_field in ['Ones', 'Density']:
                     yield assert_equal, frb[slc_field].info['data_source'], \

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/extern/__init__.py
--- /dev/null
+++ b/yt/extern/__init__.py
@@ -0,0 +1,4 @@
+"""
+This packages contains python packages that are bundled with yt
+and are developed by 3rd party upstream.
+"""

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/extern/parameterized.py
--- /dev/null
+++ b/yt/extern/parameterized.py
@@ -0,0 +1,226 @@
+import re
+import inspect
+from functools import wraps
+from collections import namedtuple
+
+from nose.tools import nottest
+from unittest import TestCase
+
+from . import six
+
+if six.PY3:
+    def new_instancemethod(f, *args):
+        return f
+else:
+    import new
+    new_instancemethod = new.instancemethod
+
+_param = namedtuple("param", "args kwargs")
+
+class param(_param):
+    """ Represents a single parameter to a test case.
+
+        For example::
+
+            >>> p = param("foo", bar=16)
+            >>> p
+            param("foo", bar=16)
+            >>> p.args
+            ('foo', )
+            >>> p.kwargs
+            {'bar': 16}
+
+        Intended to be used as an argument to ``@parameterized``::
+
+            @parameterized([
+                param("foo", bar=16),
+            ])
+            def test_stuff(foo, bar=16):
+                pass
+        """
+
+    def __new__(cls, *args , **kwargs):
+        return _param.__new__(cls, args, kwargs)
+
+    @classmethod
+    def explicit(cls, args=None, kwargs=None):
+        """ Creates a ``param`` by explicitly specifying ``args`` and
+            ``kwargs``::
+
+                >>> param.explicit([1,2,3])
+                param(*(1, 2, 3))
+                >>> param.explicit(kwargs={"foo": 42})
+                param(*(), **{"foo": "42"})
+            """
+        args = args or ()
+        kwargs = kwargs or {}
+        return cls(*args, **kwargs)
+
+    @classmethod
+    def from_decorator(cls, args):
+        """ Returns an instance of ``param()`` for ``@parameterized`` argument
+            ``args``::
+
+                >>> param.from_decorator((42, ))
+                param(args=(42, ), kwargs={})
+                >>> param.from_decorator("foo")
+                param(args=("foo", ), kwargs={})
+            """
+        if isinstance(args, param):
+            return args
+        if isinstance(args, six.string_types):
+            args = (args, )
+        return cls(*args)
+
+    def __repr__(self):
+        return "param(*%r, **%r)" %self
+
+class parameterized(object):
+    """ Parameterize a test case::
+
+            class TestInt(object):
+                @parameterized([
+                    ("A", 10),
+                    ("F", 15),
+                    param("10", 42, base=42)
+                ])
+                def test_int(self, input, expected, base=16):
+                    actual = int(input, base=base)
+                    assert_equal(actual, expected)
+
+            @parameterized([
+                (2, 3, 5)
+                (3, 5, 8),
+            ])
+            def test_add(a, b, expected):
+                assert_equal(a + b, expected)
+        """
+
+    def __init__(self, input):
+        self.get_input = self.input_as_callable(input)
+
+    def __call__(self, test_func):
+        self.assert_not_in_testcase_subclass()
+
+        @wraps(test_func)
+        def parameterized_helper_method(test_self=None):
+            f = test_func
+            if test_self is not None:
+                # If we are a test method (which we suppose to be true if we
+                # are being passed a "self" argument), we first need to create
+                # an instance method, attach it to the instance of the test
+                # class, then pull it back off to turn it into a bound method.
+                # If we don't do this, Nose gets cranky.
+                f = self.make_bound_method(test_self, test_func)
+            # Note: because nose is so very picky, the more obvious
+            # ``return self.yield_nose_tuples(f)`` won't work here.
+            for nose_tuple in self.yield_nose_tuples(f):
+                yield nose_tuple
+
+        test_func.__name__ = "_helper_for_%s" %(test_func.__name__, )
+        parameterized_helper_method.parameterized_input = input
+        parameterized_helper_method.parameterized_func = test_func
+        return parameterized_helper_method
+
+    def yield_nose_tuples(self, func):
+        for args in self.get_input():
+            p = param.from_decorator(args)
+            # ... then yield that as a tuple. If those steps aren't
+            # followed precicely, Nose gets upset and doesn't run the test
+            # or doesn't run setup methods.
+            yield self.param_as_nose_tuple(p, func)
+
+    def param_as_nose_tuple(self, p, func):
+        nose_func = func
+        nose_args = p.args
+        if p.kwargs:
+            nose_func = wraps(func)(lambda args, kwargs: func(*args, **kwargs))
+            nose_args = (p.args, p.kwargs)
+        return (nose_func, ) + nose_args
+
+    def make_bound_method(self, instance, func):
+        cls = type(instance)
+        im_f = new_instancemethod(func, None, cls)
+        setattr(cls, func.__name__, im_f)
+        return getattr(instance, func.__name__)
+
+    def assert_not_in_testcase_subclass(self):
+        parent_classes = self._terrible_magic_get_defining_classes()
+        if any(issubclass(cls, TestCase) for cls in parent_classes):
+            raise Exception("Warning: '@parameterized' tests won't work "
+                            "inside subclasses of 'TestCase' - use "
+                            "'@parameterized.expand' instead")
+
+    def _terrible_magic_get_defining_classes(self):
+        """ Returns the set of parent classes of the class currently being defined.
+            Will likely only work if called from the ``parameterized`` decorator.
+            This function is entirely @brandon_rhodes's fault, as he suggested
+            the implementation: http://stackoverflow.com/a/8793684/71522
+            """
+        stack = inspect.stack()
+        if len(stack) <= 4:
+            return []
+        frame = stack[4]
+        code_context = frame[4] and frame[4][0].strip()
+        if not (code_context and code_context.startswith("class ")):
+            return []
+        _, parents = code_context.split("(", 1)
+        parents, _ = parents.rsplit(")", 1)
+        return eval("[" + parents + "]", frame[0].f_globals, frame[0].f_locals)
+
+    @classmethod
+    def input_as_callable(cls, input):
+        if callable(input):
+            return lambda: cls.check_input_values(input())
+        input_values = cls.check_input_values(input)
+        return lambda: input_values
+
+    @classmethod
+    def check_input_values(cls, input_values):
+        if not hasattr(input_values, "__iter__"):
+            raise ValueError("expected iterable input; got %r" %(input, ))
+        return input_values
+
+    @classmethod
+    def expand(cls, input):
+        """ A "brute force" method of parameterizing test cases. Creates new
+            test cases and injects them into the namespace that the wrapped
+            function is being defined in. Useful for parameterizing tests in
+            subclasses of 'UnitTest', where Nose test generators don't work.
+
+            >>> @parameterized.expand([("foo", 1, 2)])
+            ... def test_add1(name, input, expected):
+            ...     actual = add1(input)
+            ...     assert_equal(actual, expected)
+            ...
+            >>> locals()
+            ... 'test_add1_foo_0': <function ...> ...
+            >>>
+            """
+
+        def parameterized_expand_wrapper(f):
+            stack = inspect.stack()
+            frame = stack[1]
+            frame_locals = frame[0].f_locals
+
+            base_name = f.__name__
+            get_input = cls.input_as_callable(input)
+            for num, args in enumerate(get_input()):
+                p = param.from_decorator(args)
+                name_suffix = "_%s" %(num, )
+                if len(p.args) > 0 and isinstance(p.args[0], six.string_types):
+                    name_suffix += "_" + cls.to_safe_name(p.args[0])
+                name = base_name + name_suffix
+                frame_locals[name] = cls.param_as_standalone_func(p, f, name)
+            return nottest(f)
+        return parameterized_expand_wrapper
+
+    @classmethod
+    def param_as_standalone_func(cls, p, func, name):
+        standalone_func = lambda *a: func(*(a + p.args), **p.kwargs)
+        standalone_func.__name__ = name
+        return standalone_func
+
+    @classmethod
+    def to_safe_name(cls, s):
+        return str(re.sub("[^a-zA-Z0-9_]", "", s))

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/extern/six.py
--- /dev/null
+++ b/yt/extern/six.py
@@ -0,0 +1,404 @@
+"""Utilities for writing code that runs on Python 2 and 3"""
+
+# Copyright (c) 2010-2013 Benjamin Peterson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import operator
+import sys
+import types
+
+__author__ = "Benjamin Peterson <benjamin at python.org>"
+__version__ = "1.3.0"
+
+
+# True if we are running on Python 3.
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    string_types = str,
+    integer_types = int,
+    class_types = type,
+    text_type = str
+    binary_type = bytes
+
+    MAXSIZE = sys.maxsize
+else:
+    string_types = basestring,
+    integer_types = (int, long)
+    class_types = (type, types.ClassType)
+    text_type = unicode
+    binary_type = str
+
+    if sys.platform.startswith("java"):
+        # Jython always uses 32 bits.
+        MAXSIZE = int((1 << 31) - 1)
+    else:
+        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
+        class X(object):
+            def __len__(self):
+                return 1 << 31
+        try:
+            len(X())
+        except OverflowError:
+            # 32-bit
+            MAXSIZE = int((1 << 31) - 1)
+        else:
+            # 64-bit
+            MAXSIZE = int((1 << 63) - 1)
+            del X
+
+
+def _add_doc(func, doc):
+    """Add documentation to a function."""
+    func.__doc__ = doc
+
+
+def _import_module(name):
+    """Import module, returning the module after the last dot."""
+    __import__(name)
+    return sys.modules[name]
+
+
+class _LazyDescr(object):
+
+    def __init__(self, name):
+        self.name = name
+
+    def __get__(self, obj, tp):
+        result = self._resolve()
+        setattr(obj, self.name, result)
+        # This is a bit ugly, but it avoids running this again.
+        delattr(tp, self.name)
+        return result
+
+
+class MovedModule(_LazyDescr):
+
+    def __init__(self, name, old, new=None):
+        super(MovedModule, self).__init__(name)
+        if PY3:
+            if new is None:
+                new = name
+            self.mod = new
+        else:
+            self.mod = old
+
+    def _resolve(self):
+        return _import_module(self.mod)
+
+
+class MovedAttribute(_LazyDescr):
+
+    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
+        super(MovedAttribute, self).__init__(name)
+        if PY3:
+            if new_mod is None:
+                new_mod = name
+            self.mod = new_mod
+            if new_attr is None:
+                if old_attr is None:
+                    new_attr = name
+                else:
+                    new_attr = old_attr
+            self.attr = new_attr
+        else:
+            self.mod = old_mod
+            if old_attr is None:
+                old_attr = name
+            self.attr = old_attr
+
+    def _resolve(self):
+        module = _import_module(self.mod)
+        return getattr(module, self.attr)
+
+
+
+class _MovedItems(types.ModuleType):
+    """Lazy loading of moved objects"""
+
+
+_moved_attributes = [
+    MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
+    MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
+    MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
+    MovedAttribute("map", "itertools", "builtins", "imap", "map"),
+    MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
+    MovedAttribute("reduce", "__builtin__", "functools"),
+    MovedAttribute("StringIO", "StringIO", "io"),
+    MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
+    MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
+
+    MovedModule("builtins", "__builtin__"),
+    MovedModule("configparser", "ConfigParser"),
+    MovedModule("copyreg", "copy_reg"),
+    MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
+    MovedModule("http_cookies", "Cookie", "http.cookies"),
+    MovedModule("html_entities", "htmlentitydefs", "html.entities"),
+    MovedModule("html_parser", "HTMLParser", "html.parser"),
+    MovedModule("http_client", "httplib", "http.client"),
+    MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+    MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
+    MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
+    MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
+    MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
+    MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
+    MovedModule("cPickle", "cPickle", "pickle"),
+    MovedModule("queue", "Queue"),
+    MovedModule("reprlib", "repr"),
+    MovedModule("socketserver", "SocketServer"),
+    MovedModule("tkinter", "Tkinter"),
+    MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
+    MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
+    MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
+    MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
+    MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
+    MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
+    MovedModule("tkinter_colorchooser", "tkColorChooser",
+                "tkinter.colorchooser"),
+    MovedModule("tkinter_commondialog", "tkCommonDialog",
+                "tkinter.commondialog"),
+    MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_font", "tkFont", "tkinter.font"),
+    MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
+    MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
+                "tkinter.simpledialog"),
+    MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
+    MovedModule("winreg", "_winreg"),
+]
+for attr in _moved_attributes:
+    setattr(_MovedItems, attr.name, attr)
+del attr
+
+moves = sys.modules[__name__ + ".moves"] = _MovedItems("moves")
+
+
+def add_move(move):
+    """Add an item to six.moves."""
+    setattr(_MovedItems, move.name, move)
+
+
+def remove_move(name):
+    """Remove item from six.moves."""
+    try:
+        delattr(_MovedItems, name)
+    except AttributeError:
+        try:
+            del moves.__dict__[name]
+        except KeyError:
+            raise AttributeError("no such move, %r" % (name,))
+
+
+if PY3:
+    _meth_func = "__func__"
+    _meth_self = "__self__"
+
+    _func_closure = "__closure__"
+    _func_code = "__code__"
+    _func_defaults = "__defaults__"
+    _func_globals = "__globals__"
+
+    _iterkeys = "keys"
+    _itervalues = "values"
+    _iteritems = "items"
+    _iterlists = "lists"
+else:
+    _meth_func = "im_func"
+    _meth_self = "im_self"
+
+    _func_closure = "func_closure"
+    _func_code = "func_code"
+    _func_defaults = "func_defaults"
+    _func_globals = "func_globals"
+
+    _iterkeys = "iterkeys"
+    _itervalues = "itervalues"
+    _iteritems = "iteritems"
+    _iterlists = "iterlists"
+
+
+try:
+    advance_iterator = next
+except NameError:
+    def advance_iterator(it):
+        return it.next()
+next = advance_iterator
+
+
+try:
+    callable = callable
+except NameError:
+    def callable(obj):
+        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
+
+
+if PY3:
+    def get_unbound_function(unbound):
+        return unbound
+
+    Iterator = object
+else:
+    def get_unbound_function(unbound):
+        return unbound.im_func
+
+    class Iterator(object):
+
+        def next(self):
+            return type(self).__next__(self)
+
+    callable = callable
+_add_doc(get_unbound_function,
+         """Get the function out of a possibly unbound function""")
+
+
+get_method_function = operator.attrgetter(_meth_func)
+get_method_self = operator.attrgetter(_meth_self)
+get_function_closure = operator.attrgetter(_func_closure)
+get_function_code = operator.attrgetter(_func_code)
+get_function_defaults = operator.attrgetter(_func_defaults)
+get_function_globals = operator.attrgetter(_func_globals)
+
+
+def iterkeys(d, **kw):
+    """Return an iterator over the keys of a dictionary."""
+    return iter(getattr(d, _iterkeys)(**kw))
+
+def itervalues(d, **kw):
+    """Return an iterator over the values of a dictionary."""
+    return iter(getattr(d, _itervalues)(**kw))
+
+def iteritems(d, **kw):
+    """Return an iterator over the (key, value) pairs of a dictionary."""
+    return iter(getattr(d, _iteritems)(**kw))
+
+def iterlists(d, **kw):
+    """Return an iterator over the (key, [values]) pairs of a dictionary."""
+    return iter(getattr(d, _iterlists)(**kw))
+
+
+if PY3:
+    def b(s):
+        return s.encode("latin-1")
+    def u(s):
+        return s
+    if sys.version_info[1] <= 1:
+        def int2byte(i):
+            return bytes((i,))
+    else:
+        # This is about 2x faster than the implementation above on 3.2+
+        int2byte = operator.methodcaller("to_bytes", 1, "big")
+    import io
+    StringIO = io.StringIO
+    BytesIO = io.BytesIO
+else:
+    def b(s):
+        return s
+    def u(s):
+        return unicode(s, "unicode_escape")
+    int2byte = chr
+    import StringIO
+    StringIO = BytesIO = StringIO.StringIO
+_add_doc(b, """Byte literal""")
+_add_doc(u, """Text literal""")
+
+
+if PY3:
+    import builtins
+    exec_ = getattr(builtins, "exec")
+
+
+    def reraise(tp, value, tb=None):
+        if value.__traceback__ is not tb:
+            raise value.with_traceback(tb)
+        raise value
+
+
+    print_ = getattr(builtins, "print")
+    del builtins
+
+else:
+    def exec_(_code_, _globs_=None, _locs_=None):
+        """Execute code in a namespace."""
+        if _globs_ is None:
+            frame = sys._getframe(1)
+            _globs_ = frame.f_globals
+            if _locs_ is None:
+                _locs_ = frame.f_locals
+            del frame
+        elif _locs_ is None:
+            _locs_ = _globs_
+        exec("""exec _code_ in _globs_, _locs_""")
+
+
+    exec_("""def reraise(tp, value, tb=None):
+    raise tp, value, tb
+""")
+
+
+    def print_(*args, **kwargs):
+        """The new-style print function."""
+        fp = kwargs.pop("file", sys.stdout)
+        if fp is None:
+            return
+        def write(data):
+            if not isinstance(data, basestring):
+                data = str(data)
+            fp.write(data)
+        want_unicode = False
+        sep = kwargs.pop("sep", None)
+        if sep is not None:
+            if isinstance(sep, unicode):
+                want_unicode = True
+            elif not isinstance(sep, str):
+                raise TypeError("sep must be None or a string")
+        end = kwargs.pop("end", None)
+        if end is not None:
+            if isinstance(end, unicode):
+                want_unicode = True
+            elif not isinstance(end, str):
+                raise TypeError("end must be None or a string")
+        if kwargs:
+            raise TypeError("invalid keyword arguments to print()")
+        if not want_unicode:
+            for arg in args:
+                if isinstance(arg, unicode):
+                    want_unicode = True
+                    break
+        if want_unicode:
+            newline = unicode("\n")
+            space = unicode(" ")
+        else:
+            newline = "\n"
+            space = " "
+        if sep is None:
+            sep = space
+        if end is None:
+            end = newline
+        for i, arg in enumerate(args):
+            if i:
+                write(sep)
+            write(arg)
+        write(end)
+
+_add_doc(reraise, """Reraise an exception.""")
+
+
+def with_metaclass(meta, base=object):
+    """Create a base class with a metaclass."""
+    return meta("NewBase", (base,), {})

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/setup.py
--- a/yt/setup.py
+++ b/yt/setup.py
@@ -9,6 +9,7 @@
     config = Configuration('yt', parent_package, top_path)
     config.add_subpackage('analysis_modules')
     config.add_subpackage('data_objects')
+    config.add_subpackage('extern')
     config.add_subpackage('frontends')
     config.add_subpackage('gui')
     config.add_subpackage('utilities')

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -33,6 +33,7 @@
 import cPickle
 import shelve
 import zlib
+import tempfile
 
 from matplotlib.testing.compare import compare_images
 from nose.plugins import Plugin
@@ -604,9 +605,11 @@
                                 self.plot_axis, self.plot_kwargs)
         attr = getattr(plot, self.attr_name)
         attr(*self.attr_args[0], **self.attr_args[1])
-        fn = plot.save()[0]
-        image = mpimg.imread(fn)
-        os.remove(fn)
+        tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+        os.close(tmpfd)
+        plot.save(name=tmpname)
+        image = mpimg.imread(tmpname)
+        os.remove(tmpname)
         return [zlib.compress(image.dumps())]
 
     def compare(self, new_result, old_result):

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/utilities/grid_data_format/tests/test_writer.py
--- a/yt/utilities/grid_data_format/tests/test_writer.py
+++ b/yt/utilities/grid_data_format/tests/test_writer.py
@@ -50,17 +50,18 @@
     tmpdir = tempfile.mkdtemp()
     tmpfile = os.path.join(tmpdir, 'test_gdf.h5')
 
-    test_pf = fake_random_pf(64)
-    write_to_gdf(test_pf, tmpfile, data_author=TEST_AUTHOR,
-                 data_comment=TEST_COMMENT)
-    del test_pf
+    try:
+        test_pf = fake_random_pf(64)
+        write_to_gdf(test_pf, tmpfile, data_author=TEST_AUTHOR,
+                     data_comment=TEST_COMMENT)
+        del test_pf
+        assert isinstance(load(tmpfile), GDFStaticOutput)
 
-    assert isinstance(load(tmpfile), GDFStaticOutput)
+        h5f = h5.File(tmpfile, 'r')
+        gdf = h5f['gridded_data_format'].attrs
+        assert_equal(gdf['data_author'], TEST_AUTHOR)
+        assert_equal(gdf['data_comment'], TEST_COMMENT)
+        h5f.close()
 
-    h5f = h5.File(tmpfile, 'r')
-    gdf = h5f['gridded_data_format'].attrs
-    assert_equal(gdf['data_author'], TEST_AUTHOR)
-    assert_equal(gdf['data_comment'], TEST_COMMENT)
-    h5f.close()
-
-    shutil.rmtree(tmpdir)
+    finally:
+        shutil.rmtree(tmpdir)

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/utilities/lib/setup.py
--- a/yt/utilities/lib/setup.py
+++ b/yt/utilities/lib/setup.py
@@ -20,36 +20,37 @@
     # Create a temporary directory
     tmpdir = tempfile.mkdtemp()
     curdir = os.getcwd()
-    os.chdir(tmpdir)
+    exit_code = 1
 
-    # Get compiler invocation
-    compiler = os.getenv('CC', 'cc')
+    try:
+        os.chdir(tmpdir)
 
-    # Attempt to compile a test script.
-    # See http://openmp.org/wp/openmp-compilers/
-    filename = r'test.c'
-    file = open(filename,'w', 0)
-    file.write(
-        "#include <omp.h>\n"
-        "#include <stdio.h>\n"
-        "int main() {\n"
-        "#pragma omp parallel\n"
-        "printf(\"Hello from thread %d, nthreads %d\\n\", omp_get_thread_num(), omp_get_num_threads());\n"
-        "}"
-        )
-    with open(os.devnull, 'w') as fnull:
-        exit_code = subprocess.call([compiler, '-fopenmp', filename],
-                                    stdout=fnull, stderr=fnull)
+        # Get compiler invocation
+        compiler = os.getenv('CC', 'cc')
 
-    # Clean up
-    file.close()
-    os.chdir(curdir)
-    shutil.rmtree(tmpdir)
+        # Attempt to compile a test script.
+        # See http://openmp.org/wp/openmp-compilers/
+        filename = r'test.c'
+        file = open(filename,'w', 0)
+        file.write(
+            "#include <omp.h>\n"
+            "#include <stdio.h>\n"
+            "int main() {\n"
+            "#pragma omp parallel\n"
+            "printf(\"Hello from thread %d, nthreads %d\\n\", omp_get_thread_num(), omp_get_num_threads());\n"
+            "}"
+            )
+        with open(os.devnull, 'w') as fnull:
+            exit_code = subprocess.call([compiler, '-fopenmp', filename],
+                                        stdout=fnull, stderr=fnull)
 
-    if exit_code == 0:
-        return True
-    else:
-        return False
+        # Clean up
+        file.close()
+    finally:
+        os.chdir(curdir)
+        shutil.rmtree(tmpdir)
+
+    return exit_code == 0
 
 def configuration(parent_package='',top_path=None):
     from numpy.distutils.misc_util import Configuration

diff -r 1b696a4c09d8fab667a676fc9e0c36542e60219a -r 7e42ac327db55ab369e31419af6f40276ca58fc7 yt/visualization/tests/test_plotwindow.py
--- a/yt/visualization/tests/test_plotwindow.py
+++ b/yt/visualization/tests/test_plotwindow.py
@@ -22,9 +22,12 @@
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
+import itertools
 import os
 import tempfile
 import shutil
+import unittest
+from yt.extern.parameterized import parameterized, param
 from yt.testing import \
     fake_random_pf, assert_equal, assert_rel_equal
 from yt.utilities.answer_testing.framework import \
@@ -65,132 +68,163 @@
 
     return image_type == os.path.splitext(fname)[1]
 
-attr_args ={ "pan"             : [( ((0.1, 0.1),), {} )],
-             "pan_rel"         : [( ((0.1, 0.1),), {} )],
-             "set_axes_unit"   : [( ("kpc",), {} ),
-                                  ( ("Mpc",), {} ),
-                                  ( (("kpc", "kpc"),), {} ),
-                                  ( (("kpc", "Mpc"),), {} )],
-             "set_buff_size"   : [( (1600,), {} ),
-                                  ( ((600, 800),), {} )],
-             "set_center"      : [( ((0.4, 0.3),), {} )],
-             "set_cmap"        : [( ('Density', 'RdBu'), {} ),
-                                  ( ('Density', 'kamae'), {} )],
-             "set_font"        : [( ({'family':'sans-serif', 'style':'italic',
-                                      'weight':'bold', 'size':24},), {} )],
-             "set_log"         : [( ('Density', False), {} )],
-             "set_window_size" : [( (7.0,), {} )],
-             "set_zlim" : [( ('Density', 1e-25, 1e-23), {} ),
-                           ( ('Density', 1e-25, None), {'dynamic_range' : 4} )],
-             "zoom" : [( (10,), {} )] }
 
-m7 = "DD0010/moving7_0010"
-wt = "WindTunnel/windtunnel_4lev_hdf5_plt_cnt_0030"
- at requires_pf(m7)
- at requires_pf(wt)
+TEST_FLNMS = [None, 'test.png', 'test.eps',
+              'test.ps', 'test.pdf']
+M7 = "DD0010/moving7_0010"
+WT = "WindTunnel/windtunnel_4lev_hdf5_plt_cnt_0030"
+
+ATTR_ARGS = {"pan": [(((0.1, 0.1), ), {})],
+             "pan_rel": [(((0.1, 0.1), ), {})],
+             "set_axes_unit": [(("kpc", ), {}),
+                               (("Mpc", ), {}),
+                               ((("kpc", "kpc"),), {}),
+                               ((("kpc", "Mpc"),), {})],
+             "set_buff_size": [((1600, ), {}),
+                               (((600, 800), ), {})],
+             "set_center": [(((0.4, 0.3), ), {})],
+             "set_cmap": [(('Density', 'RdBu'), {}),
+                          (('Density', 'kamae'), {})],
+             "set_font": [(({'family': 'sans-serif', 'style': 'italic',
+                             'weight': 'bold', 'size': 24}, ), {})],
+             "set_log": [(('Density', False), {})],
+             "set_window_size": [((7.0, ), {})],
+             "set_zlim": [(('Density', 1e-25, 1e-23), {}),
+                          (('Density', 1e-25, None), {'dynamic_range': 4})],
+             "zoom": [((10, ), {})]}
+
+
+ at requires_pf(M7)
 def test_attributes():
     """Test plot member functions that aren't callbacks"""
     plot_field = 'Density'
     decimals = 3
 
-    pf = data_dir_load(m7)
+    pf = data_dir_load(M7)
     for ax in 'xyz':
-        for attr_name in attr_args.keys():
-            for args in attr_args[attr_name]:
+        for attr_name in ATTR_ARGS.keys():
+            for args in ATTR_ARGS[attr_name]:
                 yield PlotWindowAttributeTest(pf, plot_field, ax, attr_name,
                                               args, decimals)
-    pf = data_dir_load(wt)
+
+
+ at requires_pf(WT)
+def test_attributes_wt():
+    plot_field = 'Density'
+    decimals = 3
+
+    pf = data_dir_load(WT)
     ax = 'z'
-    for attr_name in attr_args.keys():
-        for args in attr_args[attr_name]:
+    for attr_name in ATTR_ARGS.keys():
+        for args in ATTR_ARGS[attr_name]:
             yield PlotWindowAttributeTest(pf, plot_field, ax, attr_name,
                                           args, decimals)
 
-def test_setwidth():
-    pf = fake_random_pf(64)
 
-    slc = SlicePlot(pf, 0, 'Density')
+class TestSetWidth(unittest.TestCase):
 
-    yield assert_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(0.0, 1.0), (0.0, 1.0), (1.0, 1.0)]
+    pf = None
 
-    slc.set_width((0.5,0.8))
+    def setUp(self):
+        if self.pf is None:
+            self.pf = fake_random_pf(64)
+            self.slc = SlicePlot(self.pf, 0, 'Density')
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(0.25, 0.75), (0.1, 0.9), (0.5, 0.8)], 15
+    def _assert_15kpc(self):
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (15.0 / self.pf['kpc'], 15. / self.pf['kpc'])], 15)
 
-    slc.set_width(15,'kpc')
+    def _assert_15_10kpc(self):
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (-5.0 / self.pf['kpc'], 5.0 / self.pf['kpc']),
+                          (15.0 / self.pf['kpc'], 10. / self.pf['kpc'])], 15)
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (15/pf['kpc'], 15/pf['kpc'])], 15
+    def test_set_width_one(self):
+        assert_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                     [(0.0, 1.0), (0.0, 1.0), (1.0, 1.0)])
 
-    slc.set_width((15,'kpc'))
+    def test_set_width_nonequal(self):
+        self.slc.set_width((0.5, 0.8))
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(0.25, 0.75), (0.1, 0.9), (0.5, 0.8)], 15)
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (15/pf['kpc'], 15/pf['kpc'])], 15
+    def test_twoargs_eq(self):
+        self.slc.set_width(15, 'kpc')
+        self._assert_15kpc()
 
-    slc.set_width(((15,'kpc'),(10,'kpc')))
+    def test_tuple_eq(self):
+        self.slc.set_width((15, 'kpc'))
+        self._assert_15kpc()
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+    def test_tuple_of_tuples_neq(self):
+        self.slc.set_width(((15, 'kpc'), (10, 'kpc')))
+        self._assert_15_10kpc()
 
-    slc.set_width(((15,'kpc'),(10000,'pc')))
+    def test_tuple_of_tuples_neq2(self):
+        self.slc.set_width(((15, 'kpc'), (10000, 'pc')))
+        self._assert_15_10kpc()
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+    def test_pair_of_tuples_neq(self):
+        self.slc.set_width((15, 'kpc'), (10000, 'pc'))
+        self._assert_15_10kpc()
 
-    slc.set_width((15,'kpc'),(10000,'pc'))
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+class TestPlotWindowSave(unittest.TestCase):
 
-def test_save():
-    """Test plot window creation and saving to disk."""
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+    @classmethod
+    def setUpClass(cls):
+        test_pf = fake_random_pf(64)
+        normal = [1, 1, 1]
+        ds_region = test_pf.h.region([0.5] * 3, [0.4] * 3, [0.6] * 3)
+        projections = []
+        projections_ds = []
+        for dim in range(3):
+            projections.append(ProjectionPlot(test_pf, dim, 'Density'))
+            projections_ds.append(ProjectionPlot(test_pf, dim, 'Density',
+                                                 data_source=ds_region))
 
-    normal = [1, 1, 1]
+        cls.slices = [SlicePlot(test_pf, dim, 'Density') for dim in range(3)]
+        cls.projections = projections
+        cls.projections_ds = projections_ds
+        cls.offaxis_slice = OffAxisSlicePlot(test_pf, normal, 'Density')
+        cls.offaxis_proj = OffAxisProjectionPlot(test_pf, normal, 'Density')
 
-    test_pf = fake_random_pf(64)
-    test_flnms = [None, 'test.png', 'test.eps',
-                  'test.ps', 'test.pdf']
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp()
+        self.curdir = os.getcwd()
+        os.chdir(self.tmpdir)
 
-    ds_region = test_pf.h.region([0.5]*3,[0.4]*3,[0.6]*3)
+    def tearDown(self):
+        os.chdir(self.curdir)
+        shutil.rmtree(self.tmpdir)
 
-    for dim in [0, 1, 2]:
-        obj = SlicePlot(test_pf, dim, 'Density')
-        for fname in test_flnms:
-            yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand(
+        param.explicit(item)
+        for item in itertools.product(range(3), TEST_FLNMS))
+    def test_slice_plot(self, dim, fname):
+        assert assert_fname(self.slices[dim].save(fname)[0])
 
-    for dim in [0, 1, 2]:
-        obj = ProjectionPlot(test_pf, dim, 'Density')
-        for fname in test_flnms:
-            yield assert_equal, assert_fname(obj.save(fname)[0]), True
-        # Test ProjectionPlot's data_source keyword
-        obj = ProjectionPlot(test_pf, dim, 'Density',
-                             data_source=ds_region)
-        obj.save()
+    @parameterized.expand(
+        param.explicit(item)
+        for item in itertools.product(range(3), TEST_FLNMS))
+    def test_projection_plot(self, dim, fname):
+        assert assert_fname(self.projections[dim].save(fname)[0])
 
-    obj = OffAxisSlicePlot(test_pf, normal, 'Density')
-    for fname in test_flnms:
-        yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand([(0, ), (1, ), (2, )])
+    def test_projection_plot_ds(self, dim):
+        self.projections_ds[dim].save()
 
-    obj = OffAxisProjectionPlot(test_pf, normal, 'Density')
-    for fname in test_flnms:
-        yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand(
+        param.explicit((fname, ))
+        for fname in TEST_FLNMS)
+    def test_offaxis_slice_plot(self, fname):
+        assert assert_fname(self.offaxis_slice.save(fname)[0])
 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
+    @parameterized.expand(
+        param.explicit((fname, ))
+        for fname in TEST_FLNMS)
+    def test_offaxis_projection_plot(self, fname):
+        assert assert_fname(self.offaxis_proj.save(fname)[0])


https://bitbucket.org/yt_analysis/yt-3.0/commits/90adcd3925c4/
Changeset:   90adcd3925c4
Branch:      yt
User:        xarthisius
Date:        2013-08-22 11:34:56
Summary:     Respect units and projected_units while creating known fields from translation table
Affected #:  1 file

diff -r 7e42ac327db55ab369e31419af6f40276ca58fc7 -r 90adcd3925c48c0c7beff50d642a8527c5180a54 yt/frontends/gdf/fields.py
--- a/yt/frontends/gdf/fields.py
+++ b/yt/frontends/gdf/fields.py
@@ -84,8 +84,11 @@
           units=r"\rm{cm}/\rm{s}")
 
 for f,v in log_translation_dict.items():
-    add_field(f, TranslationFunc(v), take_log=True)
+    add_field(f, TranslationFunc(v), take_log=True,
+              units=KnownGDFFields[v].get_units(),
+              projected_units=KnownGDFFields[v].get_projected_units())
 
 for f,v in translation_dict.items():
-    add_field(f, TranslationFunc(v), take_log=False)
-
+    add_field(f, TranslationFunc(v), take_log=False,
+              units=KnownGDFFields[v].get_units(),
+              projected_units=KnownGDFFields[v].get_projected_units())


https://bitbucket.org/yt_analysis/yt-3.0/commits/f453938f3360/
Changeset:   f453938f3360
Branch:      yt
User:        xarthisius
Date:        2013-08-22 11:35:56
Summary:     Don't treat string as an array of chars while assinging units
Affected #:  1 file

diff -r 90adcd3925c48c0c7beff50d642a8527c5180a54 -r f453938f33603440430a81fbb5a9ad6a62bd2320 yt/frontends/gdf/data_structures.py
--- a/yt/frontends/gdf/data_structures.py
+++ b/yt/frontends/gdf/data_structures.py
@@ -203,7 +203,10 @@
             else:
                 self.units[field_name] = 1.0
             if 'field_units' in current_field.attrs:
-                current_fields_unit = just_one(current_field.attrs['field_units'])
+                if type(current_field.attrs['field_units']) == str:
+                    current_fields_unit = current_field.attrs['field_units']
+                else:
+                    current_fields_unit = just_one(current_field.attrs['field_units'])
             else:
                 current_fields_unit = ""
             self._fieldinfo_known.add_field(field_name, function=NullFunc, take_log=False,


https://bitbucket.org/yt_analysis/yt-3.0/commits/43940c6b177b/
Changeset:   43940c6b177b
Branch:      yt
User:        MatthewTurk
Date:        2013-08-22 18:14:43
Summary:     Adding automatic colorbars for to_mpl to PhasePlotter.
Affected #:  1 file

diff -r f453938f33603440430a81fbb5a9ad6a62bd2320 -r 43940c6b177b36e0a69377f34cefad8ef6c6335c yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -148,15 +148,19 @@
         else:
             norm = mpl.matplotlib.colors.Normalize()
         if use_mesh:
-            pcm = axes.pcolormesh(x_bins, y_bins, self.image, norm=norm,
+            mappable = axes.pcolormesh(
+                                  x_bins, y_bins, self.image, norm=norm,
                                   shading='flat', cmap = self.cbar.cmap,
                                   rasterized=True)
             if self.x_spec.scale == 'log': axes.set_xscale("log")
             if self.y_spec.scale == 'log': axes.set_yscale("log")
         else:
-            axes.imshow(self.image, origin='lower', interpolation='nearest',
+            mappable = axes.imshow(
+                        self.image, origin='lower', interpolation='nearest',
                         cmap = self.cbar.cmap, extent = [xmi,xma,ymi,yma],
                         norm = norm)
+        cbar = figure.colorbar(mappable)
+        cbar.set_label(self.cbar.title)
         if self.x_spec.title is not None:
             axes.set_xlabel(self.x_spec.title)
         if self.y_spec.title is not None:


https://bitbucket.org/yt_analysis/yt-3.0/commits/3e72bfc43c5e/
Changeset:   3e72bfc43c5e
Branch:      yt-3.0
User:        MatthewTurk
Date:        2013-08-26 20:39:47
Summary:     Merging from yt2x branch
Affected #:  24 files

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 doc/install_script.sh
--- a/doc/install_script.sh
+++ b/doc/install_script.sh
@@ -832,8 +832,8 @@
 	    echo "Building BLAS"
 	    cd BLAS
 	    gfortran -O2 -fPIC -fno-second-underscore -c *.f
-	    ar r libfblas.a *.o &>> ${LOG_FILE}
-	    ranlib libfblas.a 1>> ${LOG_FILE}
+	    ( ar r libfblas.a *.o 2>&1 ) 1>> ${LOG_FILE}
+	    ( ranlib libfblas.a 2>&1 ) 1>> ${LOG_FILE}
 	    rm -rf *.o
 	    touch done
 	    cd ..
@@ -844,7 +844,7 @@
 	    echo "Building LAPACK"
 	    cd $LAPACK/
 	    cp INSTALL/make.inc.gfortran make.inc
-	    make lapacklib OPTS="-fPIC -O2" NOOPT="-fPIC -O0" CFLAGS=-fPIC LDFLAGS=-fPIC 1>> ${LOG_FILE} || do_exit
+	    ( make lapacklib OPTS="-fPIC -O2" NOOPT="-fPIC -O0" CFLAGS=-fPIC LDFLAGS=-fPIC 2>&1 ) 1>> ${LOG_FILE} || do_exit
 	    touch done
 	    cd ..
 	fi
@@ -943,10 +943,10 @@
 touch done
 cd $MY_PWD
 
-if !(${DEST_DIR}/bin/python2.7 -c "import readline" >> ${LOG_FILE})
+if !( ( ${DEST_DIR}/bin/python2.7 -c "import readline" 2>&1 )>> ${LOG_FILE})
 then
     echo "Installing pure-python readline"
-    ${DEST_DIR}/bin/pip install readline 1>> ${LOG_FILE}
+    ( ${DEST_DIR}/bin/pip install readline 2>&1 ) 1>> ${LOG_FILE}
 fi
 
 if [ $INST_ENZO -eq 1 ]

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/analysis_modules/halo_finding/halo_objects.py
--- a/yt/analysis_modules/halo_finding/halo_objects.py
+++ b/yt/analysis_modules/halo_finding/halo_objects.py
@@ -1062,8 +1062,9 @@
     def __init__(self, data_source, dm_only=True, redshift=-1):
         """
         Run hop on *data_source* with a given density *threshold*.  If
-        *dm_only* is True (default), only run it on the dark matter particles, otherwise
-        on all particles.  Returns an iterable collection of *HopGroup* items.
+        *dm_only* is True (default), only run it on the dark matter particles, 
+        otherwise on all particles.  Returns an iterable collection of 
+        *HopGroup* items.
         """
         self._data_source = data_source
         self.dm_only = dm_only

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/data_objects/tests/test_cutting_plane.py
--- a/yt/data_objects/tests/test_cutting_plane.py
+++ b/yt/data_objects/tests/test_cutting_plane.py
@@ -1,5 +1,6 @@
 from yt.testing import *
 import os
+import tempfile
 
 def setup():
     from yt.config import ytcfg
@@ -7,7 +8,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 def test_cutting_plane():
     for nprocs in [8, 1]:
@@ -23,7 +27,9 @@
         yield assert_equal, cut["Ones"].min(), 1.0
         yield assert_equal, cut["Ones"].max(), 1.0
         pw = cut.to_pw()
-        fns += pw.save()
+        tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+        os.close(tmpfd)
+        fns += pw.save(name=tmpname)
         frb = cut.to_frb((1.0,'unitary'), 64)
         for cut_field in ['Ones', 'Density']:
             yield assert_equal, frb[cut_field].info['data_source'], \

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/data_objects/tests/test_image_array.py
--- a/yt/data_objects/tests/test_image_array.py
+++ b/yt/data_objects/tests/test_image_array.py
@@ -1,130 +1,94 @@
-from yt.testing import *
-from yt.data_objects.image_array import ImageArray
 import numpy as np
 import os
 import tempfile
 import shutil
+import unittest
+from yt.data_objects.image_array import ImageArray
+from yt.testing import \
+    assert_equal
+
 
 def setup():
     from yt.config import ytcfg
-    ytcfg["yt","__withintesting"] = "True"
-    np.seterr(all = 'ignore')
+    ytcfg["yt", "__withintesting"] = "True"
+    np.seterr(all='ignore')
+
+
+def dummy_image(kstep, nlayers):
+    im = np.zeros([64, 128, nlayers])
+    for i in xrange(im.shape[0]):
+        for k in xrange(im.shape[2]):
+            im[i, :, k] = np.linspace(0.0, kstep * k, im.shape[1])
+    return im
+
 
 def test_rgba_rescale():
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-    im_arr = ImageArray(im)
+    im_arr = ImageArray(dummy_image(10.0, 4))
 
     new_im = im_arr.rescale(inline=False)
-    yield assert_equal, im_arr[:,:,:3].max(), 2*10.
-    yield assert_equal, im_arr[:,:,3].max(), 3*10.
-    yield assert_equal, new_im[:,:,:3].sum(axis=2).max(), 1.0 
-    yield assert_equal, new_im[:,:,3].max(), 1.0
+    yield assert_equal, im_arr[:, :, :3].max(), 2 * 10.
+    yield assert_equal, im_arr[:, :, 3].max(), 3 * 10.
+    yield assert_equal, new_im[:, :, :3].sum(axis=2).max(), 1.0
+    yield assert_equal, new_im[:, :, 3].max(), 1.0
 
     im_arr.rescale()
-    yield assert_equal, im_arr[:,:,:3].sum(axis=2).max(), 1.0
-    yield assert_equal, im_arr[:,:,3].max(), 1.0
+    yield assert_equal, im_arr[:, :, :3].sum(axis=2).max(), 1.0
+    yield assert_equal, im_arr[:, :, 3].max(), 1.0
 
-def test_image_array_hdf5():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
 
-    im = np.zeros([64,128,3])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,0.3*k, im.shape[1])
+class TestImageArray(unittest.TestCase):
 
-    myinfo = {'field':'dinosaurs', 'east_vector':np.array([1.,0.,0.]), 
-        'north_vector':np.array([0.,0.,1.]), 'normal_vector':np.array([0.,1.,0.]),  
-        'width':0.245, 'units':'cm', 'type':'rendering'}
+    tmpdir = None
+    curdir = None
 
-    im_arr = ImageArray(im, info=myinfo)
-    im_arr.save('test_3d_ImageArray')
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp()
+        self.curdir = os.getcwd()
+        os.chdir(self.tmpdir)
 
-    im = np.zeros([64,128])
-    for i in xrange(im.shape[0]):
-        im[i,:] = np.linspace(0.,0.3*k, im.shape[1])
+    def test_image_array_hdf5(self):
+        myinfo = {'field': 'dinosaurs', 'east_vector': np.array([1., 0., 0.]),
+                  'north_vector': np.array([0., 0., 1.]),
+                  'normal_vector': np.array([0., 1., 0.]),
+                  'width': 0.245, 'units': 'cm', 'type': 'rendering'}
 
-    myinfo = {'field':'dinosaurs', 'east_vector':np.array([1.,0.,0.]), 
-        'north_vector':np.array([0.,0.,1.]), 'normal_vector':np.array([0.,1.,0.]),  
-        'width':0.245, 'units':'cm', 'type':'rendering'}
+        im_arr = ImageArray(dummy_image(0.3, 3), info=myinfo)
+        im_arr.save('test_3d_ImageArray')
 
-    im_arr = ImageArray(im, info=myinfo)
-    im_arr.save('test_2d_ImageArray')
+        im = np.zeros([64, 128])
+        for i in xrange(im.shape[0]):
+            im[i, :] = np.linspace(0., 0.3 * 2, im.shape[1])
 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
+        myinfo = {'field': 'dinosaurs', 'east_vector': np.array([1., 0., 0.]),
+                  'north_vector': np.array([0., 0., 1.]),
+                  'normal_vector': np.array([0., 1., 0.]),
+                  'width': 0.245, 'units': 'cm', 'type': 'rendering'}
 
-def test_image_array_rgb_png():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+        im_arr = ImageArray(im, info=myinfo)
+        im_arr.save('test_2d_ImageArray')
 
-    im = np.zeros([64,128,3])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
+    def test_image_array_rgb_png(self):
+        im_arr = ImageArray(dummy_image(10.0, 3))
+        im_arr.write_png('standard.png')
 
-    im_arr = ImageArray(im)
-    im_arr.write_png('standard.png')
+    def test_image_array_rgba_png(self):
+        im_arr = ImageArray(dummy_image(10.0, 4))
+        im_arr.write_png('standard.png')
+        im_arr.write_png('non-scaled.png', rescale=False)
+        im_arr.write_png('black_bg.png', background='black')
+        im_arr.write_png('white_bg.png', background='white')
+        im_arr.write_png('green_bg.png', background=[0., 1., 0., 1.])
+        im_arr.write_png('transparent_bg.png', background=None)
 
-def test_image_array_rgba_png():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+    def test_image_array_background(self):
+        im_arr = ImageArray(dummy_image(10.0, 4))
+        im_arr.rescale()
+        new_im = im_arr.add_background_color([1., 0., 0., 1.], inline=False)
+        new_im.write_png('red_bg.png')
+        im_arr.add_background_color('black')
+        im_arr.write_png('black_bg2.png')
 
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-
-    im_arr = ImageArray(im)
-    im_arr.write_png('standard.png')
-    im_arr.write_png('non-scaled.png', rescale=False)
-    im_arr.write_png('black_bg.png', background='black')
-    im_arr.write_png('white_bg.png', background='white')
-    im_arr.write_png('green_bg.png', background=[0.,1.,0.,1.])
-    im_arr.write_png('transparent_bg.png', background=None)
-
-
-def test_image_array_background():
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
-
-    im = np.zeros([64,128,4])
-    for i in xrange(im.shape[0]):
-        for k in xrange(im.shape[2]):
-            im[i,:,k] = np.linspace(0.,10.*k, im.shape[1])
-
-    im_arr = ImageArray(im)
-    im_arr.rescale()
-    new_im = im_arr.add_background_color([1.,0.,0.,1.], inline=False)
-    new_im.write_png('red_bg.png')
-    im_arr.add_background_color('black')
-    im_arr.write_png('black_bg2.png')
- 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
-
-
-
-
-
-
-
-
-
-
-
-
-
+    def tearDown(self):
+        os.chdir(self.curdir)
+        # clean up
+        shutil.rmtree(self.tmpdir)

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/data_objects/tests/test_projection.py
--- a/yt/data_objects/tests/test_projection.py
+++ b/yt/data_objects/tests/test_projection.py
@@ -1,5 +1,6 @@
 from yt.testing import *
 import os
+import tempfile
 
 def setup():
     from yt.config import ytcfg
@@ -7,7 +8,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 def test_projection():
     for nprocs in [8, 1]:
@@ -37,7 +41,9 @@
                 yield assert_equal, np.unique(proj["pdx"]), 1.0/(dims[xax]*2.0)
                 yield assert_equal, np.unique(proj["pdy"]), 1.0/(dims[yax]*2.0)
                 pw = proj.to_pw()
-                fns += pw.save()
+                tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+                os.close(tmpfd)
+                fns += pw.save(name=tmpname)
                 frb = proj.to_frb((1.0,'unitary'), 64)
                 for proj_field in ['Ones', 'Density']:
                     yield assert_equal, frb[proj_field].info['data_source'], \

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/data_objects/tests/test_slice.py
--- a/yt/data_objects/tests/test_slice.py
+++ b/yt/data_objects/tests/test_slice.py
@@ -27,6 +27,7 @@
 """
 import os
 import numpy as np
+import tempfile
 from nose.tools import raises
 from yt.testing import \
     fake_random_pf, assert_equal, assert_array_equal
@@ -42,7 +43,10 @@
 
 def teardown_func(fns):
     for fn in fns:
-        os.remove(fn)
+        try:
+            os.remove(fn)
+        except OSError:
+            pass
 
 
 def test_slice():
@@ -72,7 +76,9 @@
                 yield assert_equal, np.unique(slc["pdx"]), 0.5 / dims[xax]
                 yield assert_equal, np.unique(slc["pdy"]), 0.5 / dims[yax]
                 pw = slc.to_pw()
-                fns += pw.save()
+                tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+                os.close(tmpfd)
+                fns += pw.save(name=tmpname)
                 frb = slc.to_frb((1.0, 'unitary'), 64)
                 for slc_field in ['Ones', 'Density']:
                     yield assert_equal, frb[slc_field].info['data_source'], \

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/extern/__init__.py
--- /dev/null
+++ b/yt/extern/__init__.py
@@ -0,0 +1,4 @@
+"""
+This packages contains python packages that are bundled with yt
+and are developed by 3rd party upstream.
+"""

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/extern/parameterized.py
--- /dev/null
+++ b/yt/extern/parameterized.py
@@ -0,0 +1,226 @@
+import re
+import inspect
+from functools import wraps
+from collections import namedtuple
+
+from nose.tools import nottest
+from unittest import TestCase
+
+from . import six
+
+if six.PY3:
+    def new_instancemethod(f, *args):
+        return f
+else:
+    import new
+    new_instancemethod = new.instancemethod
+
+_param = namedtuple("param", "args kwargs")
+
+class param(_param):
+    """ Represents a single parameter to a test case.
+
+        For example::
+
+            >>> p = param("foo", bar=16)
+            >>> p
+            param("foo", bar=16)
+            >>> p.args
+            ('foo', )
+            >>> p.kwargs
+            {'bar': 16}
+
+        Intended to be used as an argument to ``@parameterized``::
+
+            @parameterized([
+                param("foo", bar=16),
+            ])
+            def test_stuff(foo, bar=16):
+                pass
+        """
+
+    def __new__(cls, *args , **kwargs):
+        return _param.__new__(cls, args, kwargs)
+
+    @classmethod
+    def explicit(cls, args=None, kwargs=None):
+        """ Creates a ``param`` by explicitly specifying ``args`` and
+            ``kwargs``::
+
+                >>> param.explicit([1,2,3])
+                param(*(1, 2, 3))
+                >>> param.explicit(kwargs={"foo": 42})
+                param(*(), **{"foo": "42"})
+            """
+        args = args or ()
+        kwargs = kwargs or {}
+        return cls(*args, **kwargs)
+
+    @classmethod
+    def from_decorator(cls, args):
+        """ Returns an instance of ``param()`` for ``@parameterized`` argument
+            ``args``::
+
+                >>> param.from_decorator((42, ))
+                param(args=(42, ), kwargs={})
+                >>> param.from_decorator("foo")
+                param(args=("foo", ), kwargs={})
+            """
+        if isinstance(args, param):
+            return args
+        if isinstance(args, six.string_types):
+            args = (args, )
+        return cls(*args)
+
+    def __repr__(self):
+        return "param(*%r, **%r)" %self
+
+class parameterized(object):
+    """ Parameterize a test case::
+
+            class TestInt(object):
+                @parameterized([
+                    ("A", 10),
+                    ("F", 15),
+                    param("10", 42, base=42)
+                ])
+                def test_int(self, input, expected, base=16):
+                    actual = int(input, base=base)
+                    assert_equal(actual, expected)
+
+            @parameterized([
+                (2, 3, 5)
+                (3, 5, 8),
+            ])
+            def test_add(a, b, expected):
+                assert_equal(a + b, expected)
+        """
+
+    def __init__(self, input):
+        self.get_input = self.input_as_callable(input)
+
+    def __call__(self, test_func):
+        self.assert_not_in_testcase_subclass()
+
+        @wraps(test_func)
+        def parameterized_helper_method(test_self=None):
+            f = test_func
+            if test_self is not None:
+                # If we are a test method (which we suppose to be true if we
+                # are being passed a "self" argument), we first need to create
+                # an instance method, attach it to the instance of the test
+                # class, then pull it back off to turn it into a bound method.
+                # If we don't do this, Nose gets cranky.
+                f = self.make_bound_method(test_self, test_func)
+            # Note: because nose is so very picky, the more obvious
+            # ``return self.yield_nose_tuples(f)`` won't work here.
+            for nose_tuple in self.yield_nose_tuples(f):
+                yield nose_tuple
+
+        test_func.__name__ = "_helper_for_%s" %(test_func.__name__, )
+        parameterized_helper_method.parameterized_input = input
+        parameterized_helper_method.parameterized_func = test_func
+        return parameterized_helper_method
+
+    def yield_nose_tuples(self, func):
+        for args in self.get_input():
+            p = param.from_decorator(args)
+            # ... then yield that as a tuple. If those steps aren't
+            # followed precicely, Nose gets upset and doesn't run the test
+            # or doesn't run setup methods.
+            yield self.param_as_nose_tuple(p, func)
+
+    def param_as_nose_tuple(self, p, func):
+        nose_func = func
+        nose_args = p.args
+        if p.kwargs:
+            nose_func = wraps(func)(lambda args, kwargs: func(*args, **kwargs))
+            nose_args = (p.args, p.kwargs)
+        return (nose_func, ) + nose_args
+
+    def make_bound_method(self, instance, func):
+        cls = type(instance)
+        im_f = new_instancemethod(func, None, cls)
+        setattr(cls, func.__name__, im_f)
+        return getattr(instance, func.__name__)
+
+    def assert_not_in_testcase_subclass(self):
+        parent_classes = self._terrible_magic_get_defining_classes()
+        if any(issubclass(cls, TestCase) for cls in parent_classes):
+            raise Exception("Warning: '@parameterized' tests won't work "
+                            "inside subclasses of 'TestCase' - use "
+                            "'@parameterized.expand' instead")
+
+    def _terrible_magic_get_defining_classes(self):
+        """ Returns the set of parent classes of the class currently being defined.
+            Will likely only work if called from the ``parameterized`` decorator.
+            This function is entirely @brandon_rhodes's fault, as he suggested
+            the implementation: http://stackoverflow.com/a/8793684/71522
+            """
+        stack = inspect.stack()
+        if len(stack) <= 4:
+            return []
+        frame = stack[4]
+        code_context = frame[4] and frame[4][0].strip()
+        if not (code_context and code_context.startswith("class ")):
+            return []
+        _, parents = code_context.split("(", 1)
+        parents, _ = parents.rsplit(")", 1)
+        return eval("[" + parents + "]", frame[0].f_globals, frame[0].f_locals)
+
+    @classmethod
+    def input_as_callable(cls, input):
+        if callable(input):
+            return lambda: cls.check_input_values(input())
+        input_values = cls.check_input_values(input)
+        return lambda: input_values
+
+    @classmethod
+    def check_input_values(cls, input_values):
+        if not hasattr(input_values, "__iter__"):
+            raise ValueError("expected iterable input; got %r" %(input, ))
+        return input_values
+
+    @classmethod
+    def expand(cls, input):
+        """ A "brute force" method of parameterizing test cases. Creates new
+            test cases and injects them into the namespace that the wrapped
+            function is being defined in. Useful for parameterizing tests in
+            subclasses of 'UnitTest', where Nose test generators don't work.
+
+            >>> @parameterized.expand([("foo", 1, 2)])
+            ... def test_add1(name, input, expected):
+            ...     actual = add1(input)
+            ...     assert_equal(actual, expected)
+            ...
+            >>> locals()
+            ... 'test_add1_foo_0': <function ...> ...
+            >>>
+            """
+
+        def parameterized_expand_wrapper(f):
+            stack = inspect.stack()
+            frame = stack[1]
+            frame_locals = frame[0].f_locals
+
+            base_name = f.__name__
+            get_input = cls.input_as_callable(input)
+            for num, args in enumerate(get_input()):
+                p = param.from_decorator(args)
+                name_suffix = "_%s" %(num, )
+                if len(p.args) > 0 and isinstance(p.args[0], six.string_types):
+                    name_suffix += "_" + cls.to_safe_name(p.args[0])
+                name = base_name + name_suffix
+                frame_locals[name] = cls.param_as_standalone_func(p, f, name)
+            return nottest(f)
+        return parameterized_expand_wrapper
+
+    @classmethod
+    def param_as_standalone_func(cls, p, func, name):
+        standalone_func = lambda *a: func(*(a + p.args), **p.kwargs)
+        standalone_func.__name__ = name
+        return standalone_func
+
+    @classmethod
+    def to_safe_name(cls, s):
+        return str(re.sub("[^a-zA-Z0-9_]", "", s))

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/extern/six.py
--- /dev/null
+++ b/yt/extern/six.py
@@ -0,0 +1,404 @@
+"""Utilities for writing code that runs on Python 2 and 3"""
+
+# Copyright (c) 2010-2013 Benjamin Peterson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import operator
+import sys
+import types
+
+__author__ = "Benjamin Peterson <benjamin at python.org>"
+__version__ = "1.3.0"
+
+
+# True if we are running on Python 3.
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    string_types = str,
+    integer_types = int,
+    class_types = type,
+    text_type = str
+    binary_type = bytes
+
+    MAXSIZE = sys.maxsize
+else:
+    string_types = basestring,
+    integer_types = (int, long)
+    class_types = (type, types.ClassType)
+    text_type = unicode
+    binary_type = str
+
+    if sys.platform.startswith("java"):
+        # Jython always uses 32 bits.
+        MAXSIZE = int((1 << 31) - 1)
+    else:
+        # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
+        class X(object):
+            def __len__(self):
+                return 1 << 31
+        try:
+            len(X())
+        except OverflowError:
+            # 32-bit
+            MAXSIZE = int((1 << 31) - 1)
+        else:
+            # 64-bit
+            MAXSIZE = int((1 << 63) - 1)
+            del X
+
+
+def _add_doc(func, doc):
+    """Add documentation to a function."""
+    func.__doc__ = doc
+
+
+def _import_module(name):
+    """Import module, returning the module after the last dot."""
+    __import__(name)
+    return sys.modules[name]
+
+
+class _LazyDescr(object):
+
+    def __init__(self, name):
+        self.name = name
+
+    def __get__(self, obj, tp):
+        result = self._resolve()
+        setattr(obj, self.name, result)
+        # This is a bit ugly, but it avoids running this again.
+        delattr(tp, self.name)
+        return result
+
+
+class MovedModule(_LazyDescr):
+
+    def __init__(self, name, old, new=None):
+        super(MovedModule, self).__init__(name)
+        if PY3:
+            if new is None:
+                new = name
+            self.mod = new
+        else:
+            self.mod = old
+
+    def _resolve(self):
+        return _import_module(self.mod)
+
+
+class MovedAttribute(_LazyDescr):
+
+    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
+        super(MovedAttribute, self).__init__(name)
+        if PY3:
+            if new_mod is None:
+                new_mod = name
+            self.mod = new_mod
+            if new_attr is None:
+                if old_attr is None:
+                    new_attr = name
+                else:
+                    new_attr = old_attr
+            self.attr = new_attr
+        else:
+            self.mod = old_mod
+            if old_attr is None:
+                old_attr = name
+            self.attr = old_attr
+
+    def _resolve(self):
+        module = _import_module(self.mod)
+        return getattr(module, self.attr)
+
+
+
+class _MovedItems(types.ModuleType):
+    """Lazy loading of moved objects"""
+
+
+_moved_attributes = [
+    MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
+    MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
+    MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
+    MovedAttribute("map", "itertools", "builtins", "imap", "map"),
+    MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
+    MovedAttribute("reduce", "__builtin__", "functools"),
+    MovedAttribute("StringIO", "StringIO", "io"),
+    MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
+    MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
+
+    MovedModule("builtins", "__builtin__"),
+    MovedModule("configparser", "ConfigParser"),
+    MovedModule("copyreg", "copy_reg"),
+    MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
+    MovedModule("http_cookies", "Cookie", "http.cookies"),
+    MovedModule("html_entities", "htmlentitydefs", "html.entities"),
+    MovedModule("html_parser", "HTMLParser", "html.parser"),
+    MovedModule("http_client", "httplib", "http.client"),
+    MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+    MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
+    MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
+    MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
+    MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
+    MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
+    MovedModule("cPickle", "cPickle", "pickle"),
+    MovedModule("queue", "Queue"),
+    MovedModule("reprlib", "repr"),
+    MovedModule("socketserver", "SocketServer"),
+    MovedModule("tkinter", "Tkinter"),
+    MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
+    MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
+    MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
+    MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
+    MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
+    MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
+    MovedModule("tkinter_colorchooser", "tkColorChooser",
+                "tkinter.colorchooser"),
+    MovedModule("tkinter_commondialog", "tkCommonDialog",
+                "tkinter.commondialog"),
+    MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
+    MovedModule("tkinter_font", "tkFont", "tkinter.font"),
+    MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
+    MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
+                "tkinter.simpledialog"),
+    MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
+    MovedModule("winreg", "_winreg"),
+]
+for attr in _moved_attributes:
+    setattr(_MovedItems, attr.name, attr)
+del attr
+
+moves = sys.modules[__name__ + ".moves"] = _MovedItems("moves")
+
+
+def add_move(move):
+    """Add an item to six.moves."""
+    setattr(_MovedItems, move.name, move)
+
+
+def remove_move(name):
+    """Remove item from six.moves."""
+    try:
+        delattr(_MovedItems, name)
+    except AttributeError:
+        try:
+            del moves.__dict__[name]
+        except KeyError:
+            raise AttributeError("no such move, %r" % (name,))
+
+
+if PY3:
+    _meth_func = "__func__"
+    _meth_self = "__self__"
+
+    _func_closure = "__closure__"
+    _func_code = "__code__"
+    _func_defaults = "__defaults__"
+    _func_globals = "__globals__"
+
+    _iterkeys = "keys"
+    _itervalues = "values"
+    _iteritems = "items"
+    _iterlists = "lists"
+else:
+    _meth_func = "im_func"
+    _meth_self = "im_self"
+
+    _func_closure = "func_closure"
+    _func_code = "func_code"
+    _func_defaults = "func_defaults"
+    _func_globals = "func_globals"
+
+    _iterkeys = "iterkeys"
+    _itervalues = "itervalues"
+    _iteritems = "iteritems"
+    _iterlists = "iterlists"
+
+
+try:
+    advance_iterator = next
+except NameError:
+    def advance_iterator(it):
+        return it.next()
+next = advance_iterator
+
+
+try:
+    callable = callable
+except NameError:
+    def callable(obj):
+        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
+
+
+if PY3:
+    def get_unbound_function(unbound):
+        return unbound
+
+    Iterator = object
+else:
+    def get_unbound_function(unbound):
+        return unbound.im_func
+
+    class Iterator(object):
+
+        def next(self):
+            return type(self).__next__(self)
+
+    callable = callable
+_add_doc(get_unbound_function,
+         """Get the function out of a possibly unbound function""")
+
+
+get_method_function = operator.attrgetter(_meth_func)
+get_method_self = operator.attrgetter(_meth_self)
+get_function_closure = operator.attrgetter(_func_closure)
+get_function_code = operator.attrgetter(_func_code)
+get_function_defaults = operator.attrgetter(_func_defaults)
+get_function_globals = operator.attrgetter(_func_globals)
+
+
+def iterkeys(d, **kw):
+    """Return an iterator over the keys of a dictionary."""
+    return iter(getattr(d, _iterkeys)(**kw))
+
+def itervalues(d, **kw):
+    """Return an iterator over the values of a dictionary."""
+    return iter(getattr(d, _itervalues)(**kw))
+
+def iteritems(d, **kw):
+    """Return an iterator over the (key, value) pairs of a dictionary."""
+    return iter(getattr(d, _iteritems)(**kw))
+
+def iterlists(d, **kw):
+    """Return an iterator over the (key, [values]) pairs of a dictionary."""
+    return iter(getattr(d, _iterlists)(**kw))
+
+
+if PY3:
+    def b(s):
+        return s.encode("latin-1")
+    def u(s):
+        return s
+    if sys.version_info[1] <= 1:
+        def int2byte(i):
+            return bytes((i,))
+    else:
+        # This is about 2x faster than the implementation above on 3.2+
+        int2byte = operator.methodcaller("to_bytes", 1, "big")
+    import io
+    StringIO = io.StringIO
+    BytesIO = io.BytesIO
+else:
+    def b(s):
+        return s
+    def u(s):
+        return unicode(s, "unicode_escape")
+    int2byte = chr
+    import StringIO
+    StringIO = BytesIO = StringIO.StringIO
+_add_doc(b, """Byte literal""")
+_add_doc(u, """Text literal""")
+
+
+if PY3:
+    import builtins
+    exec_ = getattr(builtins, "exec")
+
+
+    def reraise(tp, value, tb=None):
+        if value.__traceback__ is not tb:
+            raise value.with_traceback(tb)
+        raise value
+
+
+    print_ = getattr(builtins, "print")
+    del builtins
+
+else:
+    def exec_(_code_, _globs_=None, _locs_=None):
+        """Execute code in a namespace."""
+        if _globs_ is None:
+            frame = sys._getframe(1)
+            _globs_ = frame.f_globals
+            if _locs_ is None:
+                _locs_ = frame.f_locals
+            del frame
+        elif _locs_ is None:
+            _locs_ = _globs_
+        exec("""exec _code_ in _globs_, _locs_""")
+
+
+    exec_("""def reraise(tp, value, tb=None):
+    raise tp, value, tb
+""")
+
+
+    def print_(*args, **kwargs):
+        """The new-style print function."""
+        fp = kwargs.pop("file", sys.stdout)
+        if fp is None:
+            return
+        def write(data):
+            if not isinstance(data, basestring):
+                data = str(data)
+            fp.write(data)
+        want_unicode = False
+        sep = kwargs.pop("sep", None)
+        if sep is not None:
+            if isinstance(sep, unicode):
+                want_unicode = True
+            elif not isinstance(sep, str):
+                raise TypeError("sep must be None or a string")
+        end = kwargs.pop("end", None)
+        if end is not None:
+            if isinstance(end, unicode):
+                want_unicode = True
+            elif not isinstance(end, str):
+                raise TypeError("end must be None or a string")
+        if kwargs:
+            raise TypeError("invalid keyword arguments to print()")
+        if not want_unicode:
+            for arg in args:
+                if isinstance(arg, unicode):
+                    want_unicode = True
+                    break
+        if want_unicode:
+            newline = unicode("\n")
+            space = unicode(" ")
+        else:
+            newline = "\n"
+            space = " "
+        if sep is None:
+            sep = space
+        if end is None:
+            end = newline
+        for i, arg in enumerate(args):
+            if i:
+                write(sep)
+            write(arg)
+        write(end)
+
+_add_doc(reraise, """Reraise an exception.""")
+
+
+def with_metaclass(meta, base=object):
+    """Create a base class with a metaclass."""
+    return meta("NewBase", (base,), {})

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/frontends/athena/io.py
--- a/yt/frontends/athena/io.py
+++ b/yt/frontends/athena/io.py
@@ -68,9 +68,9 @@
                 data = data[2::3].reshape(grid_dims,order='F').copy()
         f.close()
         if grid.pf.field_ordering == 1:
-            return data.T
+            return data.T.astype("float64")
         else:
-            return data
+            return data.astype("float64")
 
     def _read_data_slice(self, grid, field, axis, coord):
         sl = [slice(None), slice(None), slice(None)]

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/frontends/gdf/data_structures.py
--- a/yt/frontends/gdf/data_structures.py
+++ b/yt/frontends/gdf/data_structures.py
@@ -224,7 +224,10 @@
             else:
                 self.units[field_name] = 1.0
             if 'field_units' in current_field.attrs:
-                current_fields_unit = just_one(current_field.attrs['field_units'])
+                if type(current_field.attrs['field_units']) == str:
+                    current_fields_unit = current_field.attrs['field_units']
+                else:
+                    current_fields_unit = just_one(current_field.attrs['field_units'])
             else:
                 current_fields_unit = ""
             self._fieldinfo_known.add_field(field_name, function=NullFunc, take_log=False,

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/frontends/gdf/fields.py
--- a/yt/frontends/gdf/fields.py
+++ b/yt/frontends/gdf/fields.py
@@ -84,8 +84,11 @@
           units=r"\rm{cm}/\rm{s}")
 
 for f,v in log_translation_dict.items():
-    add_field(f, TranslationFunc(v), take_log=True)
+    add_field(f, TranslationFunc(v), take_log=True,
+              units=KnownGDFFields[v].get_units(),
+              projected_units=KnownGDFFields[v].get_projected_units())
 
 for f,v in translation_dict.items():
-    add_field(f, TranslationFunc(v), take_log=False)
-
+    add_field(f, TranslationFunc(v), take_log=False,
+              units=KnownGDFFields[v].get_units(),
+              projected_units=KnownGDFFields[v].get_projected_units())

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/mods.py
--- a/yt/mods.py
+++ b/yt/mods.py
@@ -144,7 +144,8 @@
     get_multi_plot, FixedResolutionBuffer, ObliqueFixedResolutionBuffer, \
     callback_registry, write_bitmap, write_image, annotate_image, \
     apply_colormap, scale_image, write_projection, write_fits, \
-    SlicePlot, OffAxisSlicePlot, ProjectionPlot, OffAxisProjectionPlot
+    SlicePlot, OffAxisSlicePlot, ProjectionPlot, OffAxisProjectionPlot, \
+    show_colormaps
 
 from yt.visualization.volume_rendering.api import \
     ColorTransferFunction, PlanckTransferFunction, ProjectionTransferFunction, \

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/setup.py
--- a/yt/setup.py
+++ b/yt/setup.py
@@ -9,6 +9,7 @@
     config = Configuration('yt', parent_package, top_path)
     config.add_subpackage('analysis_modules')
     config.add_subpackage('data_objects')
+    config.add_subpackage('extern')
     config.add_subpackage('frontends')
     config.add_subpackage('geometry')
     config.add_subpackage('gui')

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/utilities/answer_testing/framework.py
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -33,6 +33,7 @@
 import cPickle
 import shelve
 import zlib
+import tempfile
 
 from matplotlib.testing.compare import compare_images
 from nose.plugins import Plugin
@@ -604,9 +605,11 @@
                                 self.plot_axis, self.plot_kwargs)
         attr = getattr(plot, self.attr_name)
         attr(*self.attr_args[0], **self.attr_args[1])
-        fn = plot.save()[0]
-        image = mpimg.imread(fn)
-        os.remove(fn)
+        tmpfd, tmpname = tempfile.mkstemp(suffix='.png')
+        os.close(tmpfd)
+        plot.save(name=tmpname)
+        image = mpimg.imread(tmpname)
+        os.remove(tmpname)
         return [zlib.compress(image.dumps())]
 
     def compare(self, new_result, old_result):

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/utilities/grid_data_format/tests/test_writer.py
--- a/yt/utilities/grid_data_format/tests/test_writer.py
+++ b/yt/utilities/grid_data_format/tests/test_writer.py
@@ -50,17 +50,18 @@
     tmpdir = tempfile.mkdtemp()
     tmpfile = os.path.join(tmpdir, 'test_gdf.h5')
 
-    test_pf = fake_random_pf(64)
-    write_to_gdf(test_pf, tmpfile, data_author=TEST_AUTHOR,
-                 data_comment=TEST_COMMENT)
-    del test_pf
+    try:
+        test_pf = fake_random_pf(64)
+        write_to_gdf(test_pf, tmpfile, data_author=TEST_AUTHOR,
+                     data_comment=TEST_COMMENT)
+        del test_pf
+        assert isinstance(load(tmpfile), GDFStaticOutput)
 
-    assert isinstance(load(tmpfile), GDFStaticOutput)
+        h5f = h5.File(tmpfile, 'r')
+        gdf = h5f['gridded_data_format'].attrs
+        assert_equal(gdf['data_author'], TEST_AUTHOR)
+        assert_equal(gdf['data_comment'], TEST_COMMENT)
+        h5f.close()
 
-    h5f = h5.File(tmpfile, 'r')
-    gdf = h5f['gridded_data_format'].attrs
-    assert_equal(gdf['data_author'], TEST_AUTHOR)
-    assert_equal(gdf['data_comment'], TEST_COMMENT)
-    h5f.close()
-
-    shutil.rmtree(tmpdir)
+    finally:
+        shutil.rmtree(tmpdir)

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/utilities/lib/setup.py
--- a/yt/utilities/lib/setup.py
+++ b/yt/utilities/lib/setup.py
@@ -20,36 +20,37 @@
     # Create a temporary directory
     tmpdir = tempfile.mkdtemp()
     curdir = os.getcwd()
-    os.chdir(tmpdir)
+    exit_code = 1
 
-    # Get compiler invocation
-    compiler = os.getenv('CC', 'cc')
+    try:
+        os.chdir(tmpdir)
 
-    # Attempt to compile a test script.
-    # See http://openmp.org/wp/openmp-compilers/
-    filename = r'test.c'
-    file = open(filename,'w', 0)
-    file.write(
-        "#include <omp.h>\n"
-        "#include <stdio.h>\n"
-        "int main() {\n"
-        "#pragma omp parallel\n"
-        "printf(\"Hello from thread %d, nthreads %d\\n\", omp_get_thread_num(), omp_get_num_threads());\n"
-        "}"
-        )
-    with open(os.devnull, 'w') as fnull:
-        exit_code = subprocess.call([compiler, '-fopenmp', filename],
-                                    stdout=fnull, stderr=fnull)
+        # Get compiler invocation
+        compiler = os.getenv('CC', 'cc')
 
-    # Clean up
-    file.close()
-    os.chdir(curdir)
-    shutil.rmtree(tmpdir)
+        # Attempt to compile a test script.
+        # See http://openmp.org/wp/openmp-compilers/
+        filename = r'test.c'
+        file = open(filename,'w', 0)
+        file.write(
+            "#include <omp.h>\n"
+            "#include <stdio.h>\n"
+            "int main() {\n"
+            "#pragma omp parallel\n"
+            "printf(\"Hello from thread %d, nthreads %d\\n\", omp_get_thread_num(), omp_get_num_threads());\n"
+            "}"
+            )
+        with open(os.devnull, 'w') as fnull:
+            exit_code = subprocess.call([compiler, '-fopenmp', filename],
+                                        stdout=fnull, stderr=fnull)
 
-    if exit_code == 0:
-        return True
-    else:
-        return False
+        # Clean up
+        file.close()
+    finally:
+        os.chdir(curdir)
+        shutil.rmtree(tmpdir)
+
+    return exit_code == 0
 
 def configuration(parent_package='',top_path=None):
     from numpy.distutils.misc_util import Configuration

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/visualization/_colormap_data.py
--- a/yt/visualization/_colormap_data.py
+++ b/yt/visualization/_colormap_data.py
@@ -7798,3 +7798,11 @@
 color_map_luts['Rainbow18'] = color_map_luts['idl38']
 color_map_luts['Rainbow + white'] = color_map_luts['idl39']
 color_map_luts['Rainbow + black'] = color_map_luts['idl40']
+
+# Create a reversed LUT for each of the above defined LUTs
+# and append a "_r" (for reversal. consistent with MPL convention).
+# So for example, the reversal of "Waves" is "Waves_r"
+temp = {}
+for k,v in color_map_luts.iteritems():
+    temp[k+"_r"] = (v[0][::-1], v[1][::-1], v[2][::-1], v[3][::-1])
+color_map_luts.update(temp)

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/visualization/api.py
--- a/yt/visualization/api.py
+++ b/yt/visualization/api.py
@@ -29,7 +29,8 @@
 """
 
 from color_maps import \
-    add_cmap
+    add_cmap, \
+    show_colormaps
 
 from plot_collection import \
     PlotCollection, \

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/visualization/color_maps.py
--- a/yt/visualization/color_maps.py
+++ b/yt/visualization/color_maps.py
@@ -145,3 +145,56 @@
     b = cmap._lut[:-3, 2]
     a = np.ones(b.shape)
     return [r, g, b, a]
+
+def show_colormaps(subset = "all", filename=None):
+    """
+    Displays the colormaps available to yt.  Note, most functions can use
+    both the matplotlib and the native yt colormaps; however, there are 
+    some special functions existing within image_writer.py (e.g. write_image()
+    write_fits(), write_bitmap(), etc.), which cannot access the matplotlib
+    colormaps.
+
+    In addition to the colormaps listed, one can access the reverse of each 
+    colormap by appending a "_r" to any map.
+    
+    Parameters
+    ----------
+
+    subset : string, opt
+
+        valid values : "all", "yt_native"
+        default : "all"
+
+        As mentioned above, a few functions can only access yt_native 
+        colormaps.  To display only the yt_native colormaps, set this
+        to "yt_native".  
+
+    filename : string, opt
+
+        default: None
+
+        If filename is set, then it will save the colormaps to an output
+        file.  If it is not set, it will "show" the result interactively.
+    """
+    import pylab as pl
+
+    a=np.outer(np.arange(0,1,0.01), np.ones(10))
+    if (subset == "all"):
+        maps = [ m for m in pl.cm.datad if (not m.startswith("idl")) & (not m.endswith("_r"))]
+    if (subset == "yt_native"):
+        maps = [ m for m in _cm.color_map_luts if (not m.startswith("idl")) & (not m.endswith("_r"))]
+    maps = list(set(maps))
+    maps.sort()
+    # scale the image size by the number of cmaps
+    pl.figure(figsize=(2.*len(maps)/10.,6))
+    pl.subplots_adjust(top=0.7,bottom=0.05,left=0.01,right=0.99)
+    l = len(maps)+1
+    for i,m in enumerate(maps):
+        pl.subplot(1,l,i+1)
+        pl.axis("off")
+        pl.imshow(a, aspect='auto',cmap=pl.get_cmap(m),origin="lower")      
+        pl.title(m,rotation=90, fontsize=10, verticalalignment='bottom')
+    if filename is not None:
+        pl.savefig(filename, dpi=100, facecolor='gray') 
+    else:  
+        pl.show()

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/visualization/plot_modifications.py
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -45,6 +45,7 @@
     sec_per_Gyr, sec_per_Myr, \
     sec_per_kyr, sec_per_year, \
     sec_per_day, sec_per_hr
+from yt.visualization.image_writer import apply_colormap
 
 import _MPL
 
@@ -176,7 +177,8 @@
 
 class QuiverCallback(PlotCallback):
     """
-    annotate_quiver(field_x, field_y, factor, scale=None, scale_units=None, normalize=False):
+    annotate_quiver(field_x, field_y, factor=16, scale=None, scale_units=None, 
+                    normalize=False, bv_x=0, bv_y=0):
 
     Adds a 'quiver' plot to any plot, using the *field_x* and *field_y*
     from the associated data, skipping every *factor* datapoints
@@ -230,8 +232,8 @@
 
 class ContourCallback(PlotCallback):
     """
-    annotate_contour(self, field, ncont=5, factor=4, take_log=None, clim=None,
-                     plot_args = None):
+    annotate_contour(field, ncont=5, factor=4, take_log=None, clim=None,
+                     plot_args=None, label=False, label_args=None):
 
     Add contours in *field* to the plot.  *ncont* governs the number of
     contours generated, *factor* governs the number of points used in the
@@ -338,18 +340,21 @@
 
 class GridBoundaryCallback(PlotCallback):
     """
-    annotate_grids(alpha=1.0, min_pix=1, draw_ids=False, periodic=True)
+    annotate_grids(alpha=0.7, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
+                 min_level=None, max_level=None, cmap='B-W LINEAR_r'):
 
-    Adds grid boundaries to a plot, optionally with *alpha*-blending.
-    Cuttoff for display is at *min_pix* wide.
-    *draw_ids* puts the grid id in the corner of the grid.  (Not so great in projections...)
-    Grids must be wider than *min_pix_ids* otherwise the ID will not be drawn.  If *min_level* 
-    is specified, only draw grids at or above min_level.  If *max_level* is specified, only 
-    draw grids at or below max_level.
+    Draws grids on an existing PlotWindow object.
+    Adds grid boundaries to a plot, optionally with alpha-blending. By default, 
+    colors different levels of grids with different colors going from white to
+    black, but you can change to any arbitrary colormap with cmap keyword 
+    (or all black cells for all levels with cmap=None).  Cuttoff for display is at 
+    min_pix wide. draw_ids puts the grid id in the corner of the grid. 
+    (Not so great in projections...).  One can set min and maximum level of
+    grids to display.
     """
     _type_name = "grids"
-    def __init__(self, alpha=1.0, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
-                 min_level=None, max_level=None):
+    def __init__(self, alpha=0.7, min_pix=1, min_pix_ids=20, draw_ids=False, periodic=True, 
+                 min_level=None, max_level=None, cmap='B-W LINEAR_r'):
         PlotCallback.__init__(self)
         self.alpha = alpha
         self.min_pix = min_pix
@@ -358,6 +363,7 @@
         self.periodic = periodic
         self.min_level = min_level
         self.max_level = max_level
+        self.cmap = cmap
 
     def __call__(self, plot):
         x0, x1 = plot.xlim
@@ -375,15 +381,16 @@
             pxs, pys = np.mgrid[-1:1:3j,-1:1:3j]
         else:
             pxs, pys = np.mgrid[0:0:1j,0:0:1j]
-        GLE = plot.data.pf.h.grid_left_edge
-        GRE = plot.data.pf.h.grid_right_edge
-        grid_levels = plot.data.pf.h.grid_levels[:,0]
+        GLE = plot.data.grid_left_edge
+        GRE = plot.data.grid_right_edge
+        levels = plot.data.grid_levels[:,0]
         min_level = self.min_level
-        max_level = self.min_level
+        max_level = self.max_level
+        if max_level is None:
+            max_level = plot.data.pf.h.max_level
         if min_level is None:
             min_level = 0
-        if max_level is None:
-            max_level = plot.data.pf.h.max_level
+
         for px_off, py_off in zip(pxs.ravel(), pys.ravel()):
             pxo = px_off * dom[px_index]
             pyo = py_off * dom[py_index]
@@ -393,19 +400,28 @@
             right_edge_y = (GRE[:,py_index]+pyo-y0)*dy + yy0
             visible =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix ) & \
                        ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix ) & \
-                       ( grid_levels >= min_level) & \
-                       ( grid_levels <= max_level)
+                       ( levels >= min_level) & \
+                       ( levels <= max_level)
+
+            if self.cmap is not None: 
+                edgecolors = apply_colormap(levels[(levels <= max_level) & (levels >= min_level)]*1.0,
+                                  color_bounds=[0,plot.data.pf.h.max_level],
+                                  cmap_name=self.cmap)[0,:,:]*1.0/255.
+                edgecolors[:,3] = self.alpha
+            else:
+                edgecolors = (0.0,0.0,0.0,self.alpha)
+
             if visible.nonzero()[0].size == 0: continue
             verts = np.array(
                 [(left_edge_x, left_edge_x, right_edge_x, right_edge_x),
                  (left_edge_y, right_edge_y, right_edge_y, left_edge_y)])
             verts=verts.transpose()[visible,:,:]
-            edgecolors = (0.0,0.0,0.0,self.alpha)
             grid_collection = matplotlib.collections.PolyCollection(
                 verts, facecolors="none",
                 edgecolors=edgecolors)
             plot._axes.hold(True)
             plot._axes.add_collection(grid_collection)
+
             if self.draw_ids:
                 visible_ids =  ( xpix * (right_edge_x - left_edge_x) / (xx1 - xx0) > self.min_pix_ids ) & \
                                ( ypix * (right_edge_y - left_edge_y) / (yy1 - yy0) > self.min_pix_ids )

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/visualization/profile_plotter.py
--- a/yt/visualization/profile_plotter.py
+++ b/yt/visualization/profile_plotter.py
@@ -148,15 +148,19 @@
         else:
             norm = mpl.matplotlib.colors.Normalize()
         if use_mesh:
-            pcm = axes.pcolormesh(x_bins, y_bins, self.image, norm=norm,
+            mappable = axes.pcolormesh(
+                                  x_bins, y_bins, self.image, norm=norm,
                                   shading='flat', cmap = self.cbar.cmap,
                                   rasterized=True)
             if self.x_spec.scale == 'log': axes.set_xscale("log")
             if self.y_spec.scale == 'log': axes.set_yscale("log")
         else:
-            axes.imshow(self.image, origin='lower', interpolation='nearest',
+            mappable = axes.imshow(
+                        self.image, origin='lower', interpolation='nearest',
                         cmap = self.cbar.cmap, extent = [xmi,xma,ymi,yma],
                         norm = norm)
+        cbar = figure.colorbar(mappable)
+        cbar.set_label(self.cbar.title)
         if self.x_spec.title is not None:
             axes.set_xlabel(self.x_spec.title)
         if self.y_spec.title is not None:

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/visualization/tests/test_plotwindow.py
--- a/yt/visualization/tests/test_plotwindow.py
+++ b/yt/visualization/tests/test_plotwindow.py
@@ -22,9 +22,12 @@
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
+import itertools
 import os
 import tempfile
 import shutil
+import unittest
+from yt.extern.parameterized import parameterized, param
 from yt.testing import \
     fake_random_pf, assert_equal, assert_rel_equal
 from yt.utilities.answer_testing.framework import \
@@ -65,132 +68,163 @@
 
     return image_type == os.path.splitext(fname)[1]
 
-attr_args ={ "pan"             : [( ((0.1, 0.1),), {} )],
-             "pan_rel"         : [( ((0.1, 0.1),), {} )],
-             "set_axes_unit"   : [( ("kpc",), {} ),
-                                  ( ("Mpc",), {} ),
-                                  ( (("kpc", "kpc"),), {} ),
-                                  ( (("kpc", "Mpc"),), {} )],
-             "set_buff_size"   : [( (1600,), {} ),
-                                  ( ((600, 800),), {} )],
-             "set_center"      : [( ((0.4, 0.3),), {} )],
-             "set_cmap"        : [( ('Density', 'RdBu'), {} ),
-                                  ( ('Density', 'kamae'), {} )],
-             "set_font"        : [( ({'family':'sans-serif', 'style':'italic',
-                                      'weight':'bold', 'size':24},), {} )],
-             "set_log"         : [( ('Density', False), {} )],
-             "set_window_size" : [( (7.0,), {} )],
-             "set_zlim" : [( ('Density', 1e-25, 1e-23), {} ),
-                           ( ('Density', 1e-25, None), {'dynamic_range' : 4} )],
-             "zoom" : [( (10,), {} )] }
 
-m7 = "DD0010/moving7_0010"
-wt = "WindTunnel/windtunnel_4lev_hdf5_plt_cnt_0030"
- at requires_pf(m7)
- at requires_pf(wt)
+TEST_FLNMS = [None, 'test.png', 'test.eps',
+              'test.ps', 'test.pdf']
+M7 = "DD0010/moving7_0010"
+WT = "WindTunnel/windtunnel_4lev_hdf5_plt_cnt_0030"
+
+ATTR_ARGS = {"pan": [(((0.1, 0.1), ), {})],
+             "pan_rel": [(((0.1, 0.1), ), {})],
+             "set_axes_unit": [(("kpc", ), {}),
+                               (("Mpc", ), {}),
+                               ((("kpc", "kpc"),), {}),
+                               ((("kpc", "Mpc"),), {})],
+             "set_buff_size": [((1600, ), {}),
+                               (((600, 800), ), {})],
+             "set_center": [(((0.4, 0.3), ), {})],
+             "set_cmap": [(('Density', 'RdBu'), {}),
+                          (('Density', 'kamae'), {})],
+             "set_font": [(({'family': 'sans-serif', 'style': 'italic',
+                             'weight': 'bold', 'size': 24}, ), {})],
+             "set_log": [(('Density', False), {})],
+             "set_window_size": [((7.0, ), {})],
+             "set_zlim": [(('Density', 1e-25, 1e-23), {}),
+                          (('Density', 1e-25, None), {'dynamic_range': 4})],
+             "zoom": [((10, ), {})]}
+
+
+ at requires_pf(M7)
 def test_attributes():
     """Test plot member functions that aren't callbacks"""
     plot_field = 'Density'
     decimals = 3
 
-    pf = data_dir_load(m7)
+    pf = data_dir_load(M7)
     for ax in 'xyz':
-        for attr_name in attr_args.keys():
-            for args in attr_args[attr_name]:
+        for attr_name in ATTR_ARGS.keys():
+            for args in ATTR_ARGS[attr_name]:
                 yield PlotWindowAttributeTest(pf, plot_field, ax, attr_name,
                                               args, decimals)
-    pf = data_dir_load(wt)
+
+
+ at requires_pf(WT)
+def test_attributes_wt():
+    plot_field = 'Density'
+    decimals = 3
+
+    pf = data_dir_load(WT)
     ax = 'z'
-    for attr_name in attr_args.keys():
-        for args in attr_args[attr_name]:
+    for attr_name in ATTR_ARGS.keys():
+        for args in ATTR_ARGS[attr_name]:
             yield PlotWindowAttributeTest(pf, plot_field, ax, attr_name,
                                           args, decimals)
 
-def test_setwidth():
-    pf = fake_random_pf(64)
 
-    slc = SlicePlot(pf, 0, 'Density')
+class TestSetWidth(unittest.TestCase):
 
-    yield assert_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(0.0, 1.0), (0.0, 1.0), (1.0, 1.0)]
+    pf = None
 
-    slc.set_width((0.5,0.8))
+    def setUp(self):
+        if self.pf is None:
+            self.pf = fake_random_pf(64)
+            self.slc = SlicePlot(self.pf, 0, 'Density')
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(0.25, 0.75), (0.1, 0.9), (0.5, 0.8)], 15
+    def _assert_15kpc(self):
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (15.0 / self.pf['kpc'], 15. / self.pf['kpc'])], 15)
 
-    slc.set_width(15,'kpc')
+    def _assert_15_10kpc(self):
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(-7.5 / self.pf['kpc'], 7.5 / self.pf['kpc']),
+                          (-5.0 / self.pf['kpc'], 5.0 / self.pf['kpc']),
+                          (15.0 / self.pf['kpc'], 10. / self.pf['kpc'])], 15)
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (15/pf['kpc'], 15/pf['kpc'])], 15
+    def test_set_width_one(self):
+        assert_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                     [(0.0, 1.0), (0.0, 1.0), (1.0, 1.0)])
 
-    slc.set_width((15,'kpc'))
+    def test_set_width_nonequal(self):
+        self.slc.set_width((0.5, 0.8))
+        assert_rel_equal([self.slc.xlim, self.slc.ylim, self.slc.width],
+                         [(0.25, 0.75), (0.1, 0.9), (0.5, 0.8)], 15)
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (15/pf['kpc'], 15/pf['kpc'])], 15
+    def test_twoargs_eq(self):
+        self.slc.set_width(15, 'kpc')
+        self._assert_15kpc()
 
-    slc.set_width(((15,'kpc'),(10,'kpc')))
+    def test_tuple_eq(self):
+        self.slc.set_width((15, 'kpc'))
+        self._assert_15kpc()
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+    def test_tuple_of_tuples_neq(self):
+        self.slc.set_width(((15, 'kpc'), (10, 'kpc')))
+        self._assert_15_10kpc()
 
-    slc.set_width(((15,'kpc'),(10000,'pc')))
+    def test_tuple_of_tuples_neq2(self):
+        self.slc.set_width(((15, 'kpc'), (10000, 'pc')))
+        self._assert_15_10kpc()
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+    def test_pair_of_tuples_neq(self):
+        self.slc.set_width((15, 'kpc'), (10000, 'pc'))
+        self._assert_15_10kpc()
 
-    slc.set_width((15,'kpc'),(10000,'pc'))
 
-    yield assert_rel_equal, [slc.xlim, slc.ylim, slc.width], \
-        [(-7.5/pf['kpc'], 7.5/pf['kpc']),
-         (-5/pf['kpc'], 5/pf['kpc']),
-         (15/pf['kpc'], 10/pf['kpc'])], 15
+class TestPlotWindowSave(unittest.TestCase):
 
-def test_save():
-    """Test plot window creation and saving to disk."""
-    # Perform I/O in safe place instead of yt main dir
-    tmpdir = tempfile.mkdtemp()
-    curdir = os.getcwd()
-    os.chdir(tmpdir)
+    @classmethod
+    def setUpClass(cls):
+        test_pf = fake_random_pf(64)
+        normal = [1, 1, 1]
+        ds_region = test_pf.h.region([0.5] * 3, [0.4] * 3, [0.6] * 3)
+        projections = []
+        projections_ds = []
+        for dim in range(3):
+            projections.append(ProjectionPlot(test_pf, dim, 'Density'))
+            projections_ds.append(ProjectionPlot(test_pf, dim, 'Density',
+                                                 data_source=ds_region))
 
-    normal = [1, 1, 1]
+        cls.slices = [SlicePlot(test_pf, dim, 'Density') for dim in range(3)]
+        cls.projections = projections
+        cls.projections_ds = projections_ds
+        cls.offaxis_slice = OffAxisSlicePlot(test_pf, normal, 'Density')
+        cls.offaxis_proj = OffAxisProjectionPlot(test_pf, normal, 'Density')
 
-    test_pf = fake_random_pf(64)
-    test_flnms = [None, 'test.png', 'test.eps',
-                  'test.ps', 'test.pdf']
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp()
+        self.curdir = os.getcwd()
+        os.chdir(self.tmpdir)
 
-    ds_region = test_pf.h.region([0.5]*3,[0.4]*3,[0.6]*3)
+    def tearDown(self):
+        os.chdir(self.curdir)
+        shutil.rmtree(self.tmpdir)
 
-    for dim in [0, 1, 2]:
-        obj = SlicePlot(test_pf, dim, 'Density')
-        for fname in test_flnms:
-            yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand(
+        param.explicit(item)
+        for item in itertools.product(range(3), TEST_FLNMS))
+    def test_slice_plot(self, dim, fname):
+        assert assert_fname(self.slices[dim].save(fname)[0])
 
-    for dim in [0, 1, 2]:
-        obj = ProjectionPlot(test_pf, dim, 'Density')
-        for fname in test_flnms:
-            yield assert_equal, assert_fname(obj.save(fname)[0]), True
-        # Test ProjectionPlot's data_source keyword
-        obj = ProjectionPlot(test_pf, dim, 'Density',
-                             data_source=ds_region)
-        obj.save()
+    @parameterized.expand(
+        param.explicit(item)
+        for item in itertools.product(range(3), TEST_FLNMS))
+    def test_projection_plot(self, dim, fname):
+        assert assert_fname(self.projections[dim].save(fname)[0])
 
-    obj = OffAxisSlicePlot(test_pf, normal, 'Density')
-    for fname in test_flnms:
-        yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand([(0, ), (1, ), (2, )])
+    def test_projection_plot_ds(self, dim):
+        self.projections_ds[dim].save()
 
-    obj = OffAxisProjectionPlot(test_pf, normal, 'Density')
-    for fname in test_flnms:
-        yield assert_equal, assert_fname(obj.save(fname)[0]), True
+    @parameterized.expand(
+        param.explicit((fname, ))
+        for fname in TEST_FLNMS)
+    def test_offaxis_slice_plot(self, fname):
+        assert assert_fname(self.offaxis_slice.save(fname)[0])
 
-    os.chdir(curdir)
-    # clean up
-    shutil.rmtree(tmpdir)
+    @parameterized.expand(
+        param.explicit((fname, ))
+        for fname in TEST_FLNMS)
+    def test_offaxis_projection_plot(self, fname):
+        assert assert_fname(self.offaxis_proj.save(fname)[0])

diff -r 2c8e6279eb37d4966d28f951e3831e1aefea2baa -r 3e72bfc43c5eaecdd5d496c2228ca6cc85da5434 yt/visualization/volume_rendering/camera.py
--- a/yt/visualization/volume_rendering/camera.py
+++ b/yt/visualization/volume_rendering/camera.py
@@ -237,7 +237,7 @@
                    max_level=None):
         r"""Draws Grids on an existing volume rendering.
 
-        By mapping grid level to a color, drawes edges of grids on 
+        By mapping grid level to a color, draws edges of grids on 
         a volume rendering using the camera orientation.
 
         Parameters

Repository URL: https://bitbucket.org/yt_analysis/yt-3.0/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.



More information about the yt-svn mailing list