<commit_before>import os
import nifti
import numpy as np
from optparse import OptionParser, OptionGroup
import sys
import datetime, time

from pos_parameters import generic_wrapper, filename_parameter, string_parameter, list_parameter,\
                           value_parameter
from pos_deformable_wrappers import gnuplot_wrapper

#signal.correlate2?
# http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.correlate2d.html

def norm_corr_coeff_2d(a1, a2):
    """
    Calculate normalized cross correlation coefficient:
    http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation

    .. math::

    \frac{1}{n} \sum_{x,y}\frac{(f(x,y) - \overline{f})(t(x,y) - \overline{t})}{\sigma_f \sigma_t}

    """
    a1m, a2m = np.mean(a1),  np.mean(a2)

    num = np.sum( (a1 - a1m) * (a2 - a2m) )
    den = np.std(a1) * np.std(a2)

    return  num / den  * (1./a1.size)

def msq(a1, a2):
    """
    Return mean square difference of the two arrays
    """
    return np.sum(np.square(a1 - a2)) / a1.size

def avg_norm_corr_coeff_2d(a1, a2, a3):
    """
    Return cormalized correlation coefficient of a2 and (a1+a3)/2
    """

    p1 = a2
    p2 = 0.5 * ( a1 + a3)

    return norm_corr_coeff_2d(p1, p2)

def avg_msq(a1, a2, a3):
    """
    Return mean square difference of a2 and (a1+a3)/2
    """

    p1 = a2
    p2 = 0.5 * ( a1 + a3)

    return msq(p1, p2)

class evaluation_plot(generic_wrapper):
    _template = """
    set terminal svg size 700,450 dynamic enhanced fname "Verdana" fsize 12
    set out '{output_filename}'

    set title "Deformable registration evaluation plot\\n {title}"

    set autoscale y
    set autoscale x

    set xlabel "{xlabel}"
    set ylabel "{ylabel}"

    set format y "{yformat}"

    gray(n) =  255-255*(n+0.0)/({args_len}.0+5.0)
#   red(n)   = 255*( 3.0 * (n+0.0)/({args_len}+0.0) -2.0 )
#   green(n) = 255 * abs( 3.0 * (n+0.0)/({args_len}+0.0) -1.0 ) * 0.5
#   blue(n)  = 255 * (n+0.0)/({args_len}+0.0)

    gscale(n) = sprintf("#%X%X%X", gray(n), gray(n), gray(n))
#   plt(n) = sprintf("#%X%X%X", red(n), green(n), blue(n))

    plot for [n=1:{args_len}] '{input_filename}' u 0:n w lines lc rgb gscale(n) lw 0.3 title sprintf("%d",n)
#   plot for [n=1:{args_len}] '{input_filename}' u 0:n w lines lc rgb plt(n)    lw 1 title sprintf("%d",n)
    """

    _parameters = {
            'output_filename' : filename_parameter('output_filename', None),
            'title' : string_parameter('title', None),
            'xlabel' : string_parameter('xlabel', None),
            'ylabel' : string_parameter('ylabel', None),
            'yformat' : string_parameter('yformat', None),
            'args_len' : value_parameter('args_len', None),
            'input_filename' : string_parameter('input_filename', None),
            }

    _io_pass = { \
            'input_filename' : 'output_filename'
            }

class serial_alignment_evaluation(object):
    def __init__(self, options, args):
        self.options = options
        self.args = args

    def _extract_slice_to_average(self, sliceIndex):
        """
        Extract and return slice with given index as well as neighbouring
        slices according to provided slicing plane.
        """

        if self.options.slicingPlane == 0:
            slice1 = self._data[sliceIndex    , :, :]
            slice2 = self._data[sliceIndex + 1, :, :]
            slice3 = self._data[sliceIndex - 1, :, :]

        if self.options.slicingPlane == 1:
            slice1 = self._data[:, sliceIndex     , :]
            slice2 = self._data[:, sliceIndex + 1 , :]
            slice3 = self._data[:, sliceIndex - 1 , :]

        if self.options.slicingPlane == 2:
            slice1 = self._data[:, :, sliceIndex    ]
            slice2 = self._data[:, :, sliceIndex + 1]
            slice3 = self._data[:, :, sliceIndex - 1]

        return (slice1, slice2, slice3)

    def _extract_slice_pair(self, sliceIndex):
        """
        Extract slice with the given index as well as the slice with index +1
        according provided slicing plane.
        """

        if self.options.slicingPlane == 0:
            slice1 = self._data[sliceIndex    , :, :]
            slice2 = self._data[sliceIndex + 1, :, :]

        if self.options.slicingPlane == 1:
            slice1 = self._data[:, sliceIndex     , :]
            slice2 = self._data[:, sliceIndex + 1 , :]

        if self.options.slicingPlane == 2:
            slice1 = self._data[:, :, sliceIndex    ]
            slice2 = self._data[:, :, sliceIndex + 1]

        return (slice1, slice2)

    def _loadVolume(self, filename):
        """
        Load volume and from given filename and extract some information from
        header.
        """
        print >>sys.stderr, ""
        print >>sys.stderr, "_loadVolume: "
        print >>sys.stderr, "_loadVolume: Loading volume %s" % filename

        self._volume = nifti.NiftiImage(filename)

        self._data = self._volume.data
        self.volumeShape = self._data.shape

    def _define_similiarity_measures(self):
        """
        Define, assing proper metric and slice extraction functions according to
        provided command line parameters. Functions defined here are then used
        to evaluate image image simmilarities.
        """

        # The assignment is made for three functions:
        # - function for assigning mean square functions
        # - functions for calculating normalized cross correlation
        # - slice extraction function

        # If we want to use 'smoothness evaluation'
        if self.options.useSmoothnesMeasure == False:
            msq_function   = msq
            ncorr_function = norm_corr_coeff_2d
            get_slice_function = self._extract_slice_pair

        # If we want just to simply calculate difference
        # without evaluating 'smoothness measure'
        if self.options.useSmoothnesMeasure == True:
            msq_function   = avg_msq
            ncorr_function = avg_norm_corr_coeff_2d
            get_slice_function = self._extract_slice_to_average

        return msq_function, ncorr_function, get_slice_function

    def _initialize_results(self):
        """
        Initialize arrays for storing the results of the evaluation. Initialize
        source volume slicing range as well.
        """

        # Here we define slicing range. The slicing range depends on the
        # provided command line parameter - slicing plane.
        self.options.slicingRange = \
                range(1, self.volumeShape[self.options.slicingPlane] -1)

        # Arrays holding the results depend on the number of volumes to evaluate
        # and on the number of the slides.
        args_len  = len(self.args)
        slices_no = len(self.options.slicingRange)

        # Just define the arrays for the results
        self.results_msq =  np.zeros((args_len, slices_no))
        self.results_ncor = np.zeros((args_len, slices_no))

    def launch(self):
        """
        Launch all of the calculations!
        """

        # Get the image simmilarity metrics and slice assignment functions based
        # on the provided command line parameters:
        msq_function, ncorr_function, get_slice_function =\
                self._define_similiarity_measures()

        for file_index, file in enumerate(self.args):
            print >>sys.stderr, ""
            print >>sys.stderr, "#---------------------------------------------"
            print >>sys.stderr, "Processing %d of %d:\n%s" % (file_index + 1, len(self.args), file)
            print >>sys.stderr, "#---------------------------------------------"

            self._loadVolume(file)

            # If the file that is currently processed is the first one
            # we need to initialize the results arrays:
            if file_index == 0:
                self._initialize_results()

            # Then evaluate the alignment quality for the each pair (or triple)
            # of slices:
            for sliceIndex in self.options.slicingRange:
                planes = get_slice_function(sliceIndex)

                # Check if the script is asked for caculating particular
                # simmilarity measure, if it is, calulate it.

                # I need to substract 1 from sliceIndex to make it fit
                # into the results array.
                if self.options.msqFilename:
                    self.results_msq[file_index, sliceIndex -1]  = msq_function(*planes)

                # The same (-1) here:
                if self.options.ncorrFilename:
                    self.results_ncor[file_index, sliceIndex -1] = ncorr_function(*planes)

        # Save the results at the end of the calculations:
        self.save_results()

        # After saving the results, plot them
        self.plot_results()

    def save_results(self):
        """
        Save the results according to provided command line parameters.
        """

        if self.options.msqFilename:
            np.savetxt(self.options.msqFilename, self.results_msq.T)

        if self.options.ncorrFilename:
            np.savetxt(self.options.ncorrFilename, self.results_ncor.T)

    def plot_results(self):
        """
        Plot the evaluation results according to provided command line
        parameters.
        """

        if self.options.plotMsqFilename:
            self._plot_results_msq()

        if self.options.plotNcorrFilename:
            self._plot_results_ncorr()

    def _get_plot_filenames(self, naming_base):
        """
        Prepare the names for the particular plot.
        """

        plot_file = naming_base + ".plt"
        svg_file = naming_base + ".svg"
        png_file = naming_base + ".png"

        return plot_file, svg_file, png_file

    def _plot_results_msq(self):
        """
        Plot the results for mean square difference metric.
        """

        # Get names of the gnuplot plot file, output svg file,
        # and output png file for the the MSQ evaluation plot.
        plot_file, svg_file, png_file, = \
                self._get_plot_filenames(self.options.plotMsqFilename)

        evaluation_plot_kwargs = { \
                'output_filename' : svg_file,
                'xlabel' : 'Slice index',
                'ylabel' : 'MSQ',
                'yformat' : '%2.0f',
                'title' : 'Mean sqare difference between slice n and n + 1',
                'args_len' : len(self.args),
                'input_filename' : self.options.msqFilename}

        gnuplot_kwargs = {
                'plot_file'   : plot_file,
                'svg_file'    : svg_file,
                'output_file' : png_file}

        plot    = evaluation_plot(**evaluation_plot_kwargs)
        gnuplot = gnuplot_wrapper(**gnuplot_kwargs)

        # Execute plotting
        open(plot_file, 'w').write(str(plot))
        gnuplot()

    def _plot_results_ncorr(self):
        """
        Plot the results for the normalized corelation coefficient.
        """

        # Get names of the gnuplot plot file, output svg file,
        # and output png file for the the normalized correlation coefficient
        # plot
        plot_file, svg_file, png_file, = \
                self._get_plot_filenames(self.options.plotNcorrFilename)

        evaluation_plot_kwargs = { \
                'output_filename' : svg_file,
                'xlabel' : 'Slice index',
                'ylabel' : 'NCORR',
                'yformat' : '%1.2f',
                'title' : 'Correlation coeff between slice n and n + 1',
                'args_len' : len(self.args),
                'input_filename' : self.options.ncorrFilename}

        gnuplot_kwargs = {
                'plot_file'   : plot_file,
                'svg_file'    : svg_file,
                'output_file' : png_file}

        plot    = evaluation_plot(**evaluation_plot_kwargs)
        gnuplot = gnuplot_wrapper(**gnuplot_kwargs)

        # Execute plotting
        open(plot_file, 'w').write(str(plot))
        gnuplot()

    @staticmethod
    def parseArgs():
        usage = ""

        parser = OptionParser(usage = usage)

        parser.add_option('--msqFilename', default=None,
                dest='msqFilename', action='store', type='str',
                help='MSQ output file.')
        parser.add_option('--ncorrFilename', default=None,
                dest='ncorrFilename', action='store', type='str',
                help='NCORR filename')
        parser.add_option('--slicingPlane', default=1,
                dest='slicingPlane', action='store', type='int',
                help='Slicing plane')
        parser.add_option('--useSmoothnesMeasure', default=False, const=True,
                dest='useSmoothnesMeasure', action='store_const',
                help='Use smoothness measure instead of regular similarity metric.')
        parser.add_option('--plotMsqFilename', default=None,
                dest='plotMsqFilename', action='store', type='str',
                help='Name of the output svg image.')
        parser.add_option('--plotNcorrFilename', default=None,
                dest='plotNcorrFilename', action='store', type='str',
                help='Name of the output svg image.')

        (options, args) = parser.parse_args()
        return (options, args)

if __name__ == '__main__':
    options, args = serial_alignment_evaluation.parseArgs()
    evaluate = serial_alignment_evaluation(options, args)
    evaluate.launch()
<commit_msg>Extending registration evaluation plot with possibility of drawing box plots with ncorr results<commit_after>import os
import sys
import datetime, time
from optparse import OptionParser, OptionGroup

import nifti
import numpy as np
from scipy import stats

from pos_parameters import generic_wrapper, filename_parameter, string_parameter, list_parameter,\
                           value_parameter
from pos_deformable_wrappers import gnuplot_wrapper

#signal.correlate2?
# http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.correlate2d.html

def norm_corr_coeff_2d(a1, a2):
    """
    Calculate normalized cross correlation coefficient:
    http://en.wikipedia.org/wiki/Cross-correlation#Normalized_cross-correlation

    .. math::

    \frac{1}{n} \sum_{x,y}\frac{(f(x,y) - \overline{f})(t(x,y) - \overline{t})}{\sigma_f \sigma_t}

    """
    a1m, a2m = np.mean(a1),  np.mean(a2)

    num = np.sum( (a1 - a1m) * (a2 - a2m) )
    den = np.std(a1) * np.std(a2)

    return  num / den  * (1./a1.size)

def msq(a1, a2):
    """
    Return mean square difference of the two arrays
    """
    return np.sum(np.square(a1 - a2)) / a1.size

def avg_norm_corr_coeff_2d(a1, a2, a3):
    """
    Return cormalized correlation coefficient of a2 and (a1+a3)/2
    """

    p1 = a2
    p2 = 0.5 * ( a1 + a3)

    return norm_corr_coeff_2d(p1, p2)

def avg_msq(a1, a2, a3):
    """
    Return mean square difference of a2 and (a1+a3)/2
    """

    p1 = a2
    p2 = 0.5 * ( a1 + a3)

    return msq(p1, p2)

class evaluation_plot(generic_wrapper):
    _template = """
    set terminal svg size 700,450 dynamic enhanced fname "Verdana" fsize 12
    set out '{output_filename}'

    set title "Deformable registration evaluation plot\\n {title}"

    set autoscale y
    set autoscale x

    set xlabel "{xlabel}"
    set ylabel "{ylabel}"

    set format y "{yformat}"

    gray(n) =  255-255*(n+0.0)/({args_len}.0+5.0)
#   red(n)   = 255*( 3.0 * (n+0.0)/({args_len}+0.0) -2.0 )
#   green(n) = 255 * abs( 3.0 * (n+0.0)/({args_len}+0.0) -1.0 ) * 0.5
#   blue(n)  = 255 * (n+0.0)/({args_len}+0.0)

    gscale(n) = sprintf("#%X%X%X", gray(n), gray(n), gray(n))
#   plt(n) = sprintf("#%X%X%X", red(n), green(n), blue(n))

    plot for [n=1:{args_len}] '{input_filename}' u 0:n w lines lc rgb gscale(n) lw 0.3 title sprintf("%d",n)
#   plot for [n=1:{args_len}] '{input_filename}' u 0:n w lines lc rgb plt(n)    lw 1 title sprintf("%d",n)
    """

    _parameters = {
            'output_filename' : filename_parameter('output_filename', None),
            'title' : string_parameter('title', None),
            'xlabel' : string_parameter('xlabel', None),
            'ylabel' : string_parameter('ylabel', None),
            'yformat' : string_parameter('yformat', None),
            'args_len' : value_parameter('args_len', None),
            'input_filename' : string_parameter('input_filename', None),
            }

    _io_pass = { \
            'input_filename' : 'output_filename'
            }

class candlestick_plot(generic_wrapper):
    _template = """
    set terminal svg size 700,450 dynamic enhanced fname "Verdana" fsize 12
    set out '{output_filename}'

    set border 2
    set style fill solid
    unset grid

    set title "Comparison of slices simmilarity for consecutive steps of reconstructions"

    set boxwidth 0.2 absolute
    set format x ""
    set xlabel ""
    set format y "%1.1f"
    set ylabel "Normalized correlation coefficient"

    set xtics scale 0
    set ytics border in scale 2,0.5 nomirror norotate  offset character 0, 0, 0
    set yrange [0:1]
    set mytics 2

    lines=system(" cat '{input_filename}' | wc -l")
    set xrange[0:lines+1]

#    factors = "Coarse Fine Final Deformable"
#    set for [i=1:lines] xtics add (word(factors,i) i)

    plot '{input_filename}' using ($0+1):2:1:5:4 with candlesticks notitle whiskerbars lw 2 lc rgb "#aabbcc", \
         '{input_filename}' using ($0+1):3:3:3:3 with candlesticks lt -1 lw 2 lc rgb "#445566" notitle
    """

    _parameters = {
            'output_filename' : filename_parameter('output_filename', None),
            'input_filename' : string_parameter('input_filename', None),
            }

    _io_pass = { \
            'input_filename' : 'output_filename'
            }

class serial_alignment_evaluation(object):
    def __init__(self, options, args):
        self.options = options
        self.args = args

    def _extract_slice_to_average(self, sliceIndex):
        """
        Extract and return slice with given index as well as neighbouring
        slices according to provided slicing plane.
        """

        if self.options.slicingPlane == 0:
            slice1 = self._data[sliceIndex    , :, :]
            slice2 = self._data[sliceIndex + 1, :, :]
            slice3 = self._data[sliceIndex - 1, :, :]

        if self.options.slicingPlane == 1:
            slice1 = self._data[:, sliceIndex     , :]
            slice2 = self._data[:, sliceIndex + 1 , :]
            slice3 = self._data[:, sliceIndex - 1 , :]

        if self.options.slicingPlane == 2:
            slice1 = self._data[:, :, sliceIndex    ]
            slice2 = self._data[:, :, sliceIndex + 1]
            slice3 = self._data[:, :, sliceIndex - 1]

        return (slice1, slice2, slice3)

    def _extract_slice_pair(self, sliceIndex):
        """
        Extract slice with the given index as well as the slice with index +1
        according provided slicing plane.
        """

        if self.options.slicingPlane == 0:
            slice1 = self._data[sliceIndex    , :, :]
            slice2 = self._data[sliceIndex + 1, :, :]

        if self.options.slicingPlane == 1:
            slice1 = self._data[:, sliceIndex     , :]
            slice2 = self._data[:, sliceIndex + 1 , :]

        if self.options.slicingPlane == 2:
            slice1 = self._data[:, :, sliceIndex    ]
            slice2 = self._data[:, :, sliceIndex + 1]

        return (slice1, slice2)

    def _loadVolume(self, filename):
        """
        Load volume and from given filename and extract some information from
        header.
        """
        print >>sys.stderr, ""
        print >>sys.stderr, "_loadVolume: "
        print >>sys.stderr, "_loadVolume: Loading volume %s" % filename

        self._volume = nifti.NiftiImage(filename)

        self._data = self._volume.data
        self.volumeShape = self._data.shape

    def _define_similiarity_measures(self):
        """
        Define, assing proper metric and slice extraction functions according to
        provided command line parameters. Functions defined here are then used
        to evaluate image image simmilarities.
        """

        # The assignment is made for three functions:
        # - function for assigning mean square functions
        # - functions for calculating normalized cross correlation
        # - slice extraction function

        # If we want to use 'smoothness evaluation'
        if self.options.useSmoothnesMeasure == False:
            msq_function   = msq
            ncorr_function = norm_corr_coeff_2d
            get_slice_function = self._extract_slice_pair

        # If we want just to simply calculate difference
        # without evaluating 'smoothness measure'
        if self.options.useSmoothnesMeasure == True:
            msq_function   = avg_msq
            ncorr_function = avg_norm_corr_coeff_2d
            get_slice_function = self._extract_slice_to_average

        return msq_function, ncorr_function, get_slice_function

    def _initialize_results(self):
        """
        Initialize arrays for storing the results of the evaluation. Initialize
        source volume slicing range as well.
        """

        # Here we define slicing range. The slicing range depends on the
        # provided command line parameter - slicing plane.
        self.options.slicingRange = \
                range(1, self.volumeShape[self.options.slicingPlane] -1)

        # Arrays holding the results depend on the number of volumes to evaluate
        # and on the number of the slides.
        args_len  = len(self.args)
        slices_no = len(self.options.slicingRange)

        # Just define the arrays for the results
        self.results_msq =  np.zeros((args_len, slices_no))
        self.results_ncor = np.zeros((args_len, slices_no))

    def launch(self):
        """
        Launch all of the calculations!
        """

        # Get the image simmilarity metrics and slice assignment functions based
        # on the provided command line parameters:
        msq_function, ncorr_function, get_slice_function =\
                self._define_similiarity_measures()

        for file_index, file in enumerate(self.args):
            print >>sys.stderr, ""
            print >>sys.stderr, "#---------------------------------------------"
            print >>sys.stderr, "Processing %d of %d:\n%s" % (file_index + 1, len(self.args), file)
            print >>sys.stderr, "#---------------------------------------------"

            self._loadVolume(file)

            # If the file that is currently processed is the first one
            # we need to initialize the results arrays:
            if file_index == 0:
                self._initialize_results()

            # Then evaluate the alignment quality for the each pair (or triple)
            # of slices:
            for sliceIndex in self.options.slicingRange:
                planes = get_slice_function(sliceIndex)

                # Check if the script is asked for caculating particular
                # simmilarity measure, if it is, calulate it.

                # I need to substract 1 from sliceIndex to make it fit
                # into the results array.
                if self.options.msqFilename:
                    self.results_msq[file_index, sliceIndex -1]  = msq_function(*planes)

                # The same (-1) here:
                if self.options.ncorrFilename:
                    self.results_ncor[file_index, sliceIndex -1] = ncorr_function(*planes)

        # Save the results at the end of the calculations:
        self.save_results()

        # After saving the results, plot them
        self.plot_results()

    def save_results(self):
        """
        Save the results according to provided command line parameters.
        """

        if self.options.msqFilename:
            np.savetxt(self.options.msqFilename, self.results_msq.T)

        if self.options.ncorrFilename:
            np.savetxt(self.options.ncorrFilename, self.results_ncor.T)

    def plot_results(self):
        """
        Plot the evaluation results according to provided command line
        parameters.
        """

        if self.options.plotMsqFilename:
            self._plot_results_msq()

        if self.options.plotNcorrFilename:
            self._plot_results_ncorr()
            self._plot_reaults_ncorr_boxplot()

    def _get_plot_filenames(self, naming_base):
        """
        Prepare the names for the particular plot.
        """

        plot_file = naming_base + ".plt"
        svg_file = naming_base + ".svg"
        png_file = naming_base + ".png"

        return plot_file, svg_file, png_file

    def _plot_results_msq(self):
        """
        Plot the results for mean square difference metric.
        """

        # Get names of the gnuplot plot file, output svg file,
        # and output png file for the the MSQ evaluation plot.
        plot_file, svg_file, png_file, = \
                self._get_plot_filenames(self.options.plotMsqFilename)

        evaluation_plot_kwargs = { \
                'output_filename' : svg_file,
                'xlabel' : 'Slice index',
                'ylabel' : 'MSQ',
                'yformat' : '%2.0f',
                'title' : 'Mean sqare difference between slice n and n + 1',
                'args_len' : len(self.args),
                'input_filename' : self.options.msqFilename}

        gnuplot_kwargs = {
                'plot_file'   : plot_file,
                'svg_file'    : svg_file,
                'output_file' : png_file}

        plot    = evaluation_plot(**evaluation_plot_kwargs)
        gnuplot = gnuplot_wrapper(**gnuplot_kwargs)

        # Execute plotting
        open(plot_file, 'w').write(str(plot))
        gnuplot()

    def _plot_results_ncorr(self):
        """
        Plot the results for the normalized corelation coefficient.
        """

        # Get names of the gnuplot plot file, output svg file,
        # and output png file for the the normalized correlation coefficient
        # plot
        plot_file, svg_file, png_file, = \
                self._get_plot_filenames(self.options.plotNcorrFilename)

        evaluation_plot_kwargs = { \
                'output_filename' : svg_file,
                'xlabel' : 'Slice index',
                'ylabel' : 'NCORR',
                'yformat' : '%1.2f',
                'title' : 'Correlation coeff between slice n and n + 1',
                'args_len' : len(self.args),
                'input_filename' : self.options.ncorrFilename}

        gnuplot_kwargs = {
                'plot_file'   : plot_file,
                'svg_file'    : svg_file,
                'output_file' : png_file}

        plot    = evaluation_plot(**evaluation_plot_kwargs)
        gnuplot = gnuplot_wrapper(**gnuplot_kwargs)

        # Execute plotting
        open(plot_file, 'w').write(str(plot))
        gnuplot()

    def _plot_reaults_ncorr_boxplot(self):
        """
        Plot the normalized correlation coefficient as boxplot.
        """

        # Get names of the gnuplot plot file, output svg file,
        # and output png file for the the normalized correlation coefficient
        # plot
        plot_file, svg_file, png_file, = \
                self._get_plot_filenames(self.options.plotNcorrFilename + '_box')
        box_data_file = self.options.plotNcorrFilename + '_box'

        # Generate data for the boxplot and save it to disk
        np.savetxt(box_data_file, self._get_boxplot_data())

        plot_kwargs = { \
                'output_filename' : svg_file,
                'input_filename' : box_data_file}

        gnuplot_kwargs = {
                'plot_file'   : plot_file,
                'svg_file'    : svg_file,
                'output_file' : png_file}

        plot    = candlestick_plot(**plot_kwargs)
        gnuplot = gnuplot_wrapper(**gnuplot_kwargs)

        # Execute plotting
        open(plot_file, 'w').write(str(plot))
        gnuplot()

    def _get_boxplot_data(self):
        """
        Calculate the data for the boxplot:
        min, 1st quartile, mean,  3rd quartile and max value from the array
        """

        # Just create aliases to make the code less obscured
        f  = stats.scoreatpercentile
        a  = self.results_ncor
        print a.shape
        ar = range(a.shape[0])
        pc = [0, 25, 50, 75, 100]

        # Calculate data for the boxplot: min, 1st quartile, mean
        # 3rd quartile and max value from the array
        result = np.array( \
                 map(lambda y: \
                     map(lambda x: f(a[y,:],x),  pc), \
                 ar)\
                 )

        # And return the result
        return result

    @staticmethod
    def parseArgs():
        usage = ""

        parser = OptionParser(usage = usage)

        parser.add_option('--msqFilename', default=None,
                dest='msqFilename', action='store', type='str',
                help='MSQ output file.')
        parser.add_option('--ncorrFilename', default=None,
                dest='ncorrFilename', action='store', type='str',
                help='NCORR filename')
        parser.add_option('--slicingPlane', default=1,
                dest='slicingPlane', action='store', type='int',
                help='Slicing plane')
        parser.add_option('--useSmoothnesMeasure', default=False, const=True,
                dest='useSmoothnesMeasure', action='store_const',
                help='Use smoothness measure instead of regular similarity metric.')
        parser.add_option('--plotMsqFilename', default=None,
                dest='plotMsqFilename', action='store', type='str',
                help='Name of the output svg image.')
        parser.add_option('--plotNcorrFilename', default=None,
                dest='plotNcorrFilename', action='store', type='str',
                help='Name of the output svg image.')

        (options, args) = parser.parse_args()
        return (options, args)

if __name__ == '__main__':
    options, args = serial_alignment_evaluation.parseArgs()
    evaluate = serial_alignment_evaluation(options, args)
    evaluate.launch()
<|endoftext|>


<commit_before>"""
GrandFatherSon is a backup rotation calculator that implements the
`grandfather-father-son rotation scheme
<http://en.wikipedia.org/wiki/Backup_rotation_scheme#Grandfather-father-son_backup>`_.

This is usually done by keeping a certain number of daily, weekly, and
monthly backups. Older backups should be removed to reduce the amount
of space used.

Usage
-----

This module expects either ``datetime.date`` or ``datetime.datetime``
objects as inputs. As an example, let's assume you have daily backups
for the all of year 1999 that need rotating::

    >>> import datetime
    >>> start_date = datetime.date(1999, 1, 1)
    >>> end_date = datetime.date(1999, 12, 31)
    >>> backups = [start_date + datetime.timedelta(days=i)
    ...            for i in xrange((end_date - start_date).days + 1)]
    >>> backups
    [datetime.date(1999, 1, 1),
     datetime.date(1999, 1, 2),
     datetime.date(1999, 1, 3),
     ...
     datetime.date(1999, 12, 30),
     datetime.date(1999, 12, 31)]

Let's say that full backups are taken every Saturday, with incremental
backups done daily. A week, or 7 days, of incremental backups should
be kept. A months, or 4 weeks, of full backups are kept. In addition,
for three months, the first full backup is kept for each month, with
the others discarded.

It's the last day of the year and you want to figure out which backups
need to be pruned::

    >>> now = datetime.date(1999, 12, 31)

To see which files will be preserved, use the ``dates_to_keep``
function::

    >>> from grandfatherson import dates_to_keep, SATURDAY
    >>> sorted(dates_to_keep(backups, days=7, weeks=4, months=3,
    ...                      firstweekday=SATURDAY, now=now))
    [datetime.date(1999, 10, 1),
     datetime.date(1999, 11, 1),
     datetime.date(1999, 12, 1),
     datetime.date(1999, 12, 4),
     datetime.date(1999, 12, 11),
     datetime.date(1999, 12, 18),
     datetime.date(1999, 12, 25),
     datetime.date(1999, 12, 26),
     datetime.date(1999, 12, 27),
     datetime.date(1999, 12, 28),
     datetime.date(1999, 12, 29),
     datetime.date(1999, 12, 30),
     datetime.date(1999, 12, 31)]

If you leave off the ``now`` argument, it will default to using
``datetime.datetime.now()``.

To see which files should be deleted, use the ``dates_to_delete``
function::

    >>> from grandfatherson import dates_to_keep, SATURDAY
    >>> sorted(dates_to_delete(backups, days=7, weeks=4, months=3,
    ...                        firstweekday=SATURDAY, now=now))
    [datetime.date(1999, 1, 1),
     ...
     datetime.date(1999, 9, 30),
     datetime.date(1999, 10, 2),
     ...
     datetime.date(1999, 10, 31),
     datetime.date(1999, 11, 2),
     ...
     datetime.date(1999, 11, 30),
     datetime.date(1999, 12, 2),
     datetime.date(1999, 12, 3),
     datetime.date(1999, 12, 5),
     ...
     datetime.date(1999, 12, 10),
     datetime.date(1999, 12, 12),
     ...
     datetime.date(1999, 12, 17),
     datetime.date(1999, 12, 19),
     ...
     datetime.date(1999, 12, 24)]

Finally, if you need to rotate backups that have timestamps in
``datetime`` format, you can use the corresponding ``to_keep`` and
``to_delete`` functions::

    >>> now = datetime.datetime(1999, 12, 31, 23, 59, 59)
    >>> start_datetime = datetime.datetime(1999, 12, 31, 0, 0, 0)
    >>> end_datetime = datetime.datetime(1999, 12, 31, 23, 59, 59)
    >>> backups = [start_datetime + datetime.timedelta(seconds=i)
    ...            for i
    ...            in xrange((end_datetime - start_datetime).seconds + 1)]
    >>> backups
    [datetime.datetime(1999, 12, 31, 0, 0),
     datetime.datetime(1999, 12, 31, 0, 0, 1),
     datetime.datetime(1999, 12, 31, 0, 0, 2),
     ...
     datetime.datetime(1999, 12, 31, 23, 59, 58),
     datetime.datetime(1999, 12, 31, 23, 59, 59)]

    >>> from grandfatherson import to_keep
    >>> sorted(to_keep(backups, hours=2, minutes=10, seconds=10, now=now))
    [datetime.datetime(1999, 12, 31, 22, 0),
     datetime.datetime(1999, 12, 31, 23, 0),
     datetime.datetime(1999, 12, 31, 23, 50),
     ...
     datetime.datetime(1999, 12, 31, 23, 59),
     datetime.datetime(1999, 12, 31, 23, 59, 50),
     ...
     datetime.datetime(1999, 12, 31, 23, 59, 59)]

    >>> from grandfatherson import to_delete
    >>> sorted(to_delete(backups, hours=2, minutes=10, seconds=10, now=now))
    [datetime.datetime(1999, 12, 31, 0, 0),
     ...
     datetime.datetime(1999, 12, 31, 21, 59, 59),
     datetime.datetime(1999, 12, 31, 22, 0, 1),
     ...
     datetime.datetime(1999, 12, 31, 22, 59, 59),
     datetime.datetime(1999, 12, 31, 23, 0, 1),
     ...
     datetime.datetime(1999, 12, 31, 23, 49, 59),
     datetime.datetime(1999, 12, 31, 23, 50, 1),
     ...
     datetime.datetime(1999, 12, 31, 23, 58, 59),
     datetime.datetime(1999, 12, 31, 23, 59, 1),
     ...
     datetime.datetime(1999, 12, 31, 23, 59, 49)]
"""

from calendar import (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY,
                      SUNDAY)
from datetime import datetime, time
import os

from grandfatherson import filters

def to_keep(datetimes,
            years=0, months=0, weeks=0, days=0,
            hours=0, minutes=0, seconds=0,
            firstweekday=SATURDAY, now=None):
    """
    Return a set of datetimes that should be kept, out of ``datetimes``.

    Keeps up to ``years``, ``months``, ``weeks``, ``days``,
    ``hours``, ``minutes``, and ``seconds`` in the past.

    When keeping weeks, it prefers to keep ``firstweekday``, which
    defaults to Saturday.

    If ``now`` is None, it will base its calculations on
    ``datetime.datetime.now()``. Datetimes after this point will always be
    kept.
    """
    datetimes = set(datetimes)
    return (filters.Years.filter(datetimes, number=years, now=now) |
            filters.Months.filter(datetimes, number=months, now=now) |
            filters.Weeks.filter(datetimes, number=weeks,
                                 firstweekday=firstweekday, now=now) |
            filters.Days.filter(datetimes, number=days, now=now) |
            filters.Hours.filter(datetimes, number=hours, now=now) |
            filters.Minutes.filter(datetimes, number=minutes, now=now) |
            filters.Seconds.filter(datetimes, number=seconds, now=now))

def to_delete(datetimes,
              years=0, months=0, weeks=0, days=0,
              hours=0, minutes=0, seconds=0,
              firstweekday=SATURDAY, now=None):
    """
    Return a set of datetimes that should be deleted, out of ``datetimes``.

    See ``to_keep`` for a description of arguments.
    """
    datetimes = set(datetimes)
    return datetimes - to_keep(datetimes,
                               years=years, months=months,
                               weeks=weeks, days=days,
                               hours=hours, minutes=minutes, seconds=seconds,
                               firstweekday=firstweekday, now=now)

def dates_to_keep(dates,
                  years=0, months=0, weeks=0, days=0, firstweekday=SATURDAY,
                  now=None):
    """
    Return a set of dates that should be kept, out of ``dates``.

    See ``to_keep`` for a description of arguments.
    """
    datetimes = to_keep((datetime.combine(d, time()) for d in dates),
                        years=years, months=months, weeks=weeks, days=days,
                        hours=0, minutes=0, seconds=0,
                        firstweekday=firstweekday, now=now)
    return set(dt.date() for dt in datetimes)

def dates_to_delete(dates,
                    years=0, months=0, weeks=0, days=0, firstweekday=SATURDAY,
                    now=None):
    """
    Return a set of date that should be deleted, out of ``dates``.

    See ``to_keep`` for a description of arguments.
    """
    dates = set(dates)
    return dates - dates_to_keep(dates,
                                 years=years, months=months,
                                 weeks=weeks, days=days,
                                 firstweekday=firstweekday, now=now)
<commit_msg>Finish merging pull request<commit_after>"""
GrandFatherSon is a backup rotation calculator that implements the
`grandfather-father-son rotation scheme
<http://en.wikipedia.org/wiki/Backup_rotation_scheme#Grandfather-father-son_backup>`_.

This is usually done by keeping a certain number of daily, weekly, and
monthly backups. Older backups should be removed to reduce the amount
of space used.

Usage
-----

This module expects either ``datetime.date`` or ``datetime.datetime``
objects as inputs. As an example, let's assume you have daily backups
for the all of year 1999 that need rotating::

    >>> import datetime
    >>> start_date = datetime.date(1999, 1, 1)
    >>> end_date = datetime.date(1999, 12, 31)
    >>> backups = [start_date + datetime.timedelta(days=i)
    ...            for i in xrange((end_date - start_date).days + 1)]
    >>> backups
    [datetime.date(1999, 1, 1),
     datetime.date(1999, 1, 2),
     datetime.date(1999, 1, 3),
     ...
     datetime.date(1999, 12, 30),
     datetime.date(1999, 12, 31)]

Let's say that full backups are taken every Saturday, with incremental
backups done daily. A week, or 7 days, of incremental backups should
be kept. A months, or 4 weeks, of full backups are kept. In addition,
for three months, the first full backup is kept for each month, with
the others discarded.

It's the last day of the year and you want to figure out which backups
need to be pruned::

    >>> now = datetime.date(1999, 12, 31)

To see which files will be preserved, use the ``dates_to_keep``
function::

    >>> from grandfatherson import dates_to_keep, SATURDAY
    >>> sorted(dates_to_keep(backups, days=7, weeks=4, months=3,
    ...                      firstweekday=SATURDAY, now=now))
    [datetime.date(1999, 10, 1),
     datetime.date(1999, 11, 1),
     datetime.date(1999, 12, 1),
     datetime.date(1999, 12, 4),
     datetime.date(1999, 12, 11),
     datetime.date(1999, 12, 18),
     datetime.date(1999, 12, 25),
     datetime.date(1999, 12, 26),
     datetime.date(1999, 12, 27),
     datetime.date(1999, 12, 28),
     datetime.date(1999, 12, 29),
     datetime.date(1999, 12, 30),
     datetime.date(1999, 12, 31)]

If you leave off the ``now`` argument, it will default to using
``datetime.datetime.now()``.

To see which files should be deleted, use the ``dates_to_delete``
function::

    >>> from grandfatherson import dates_to_delete, SATURDAY
    >>> sorted(dates_to_delete(backups, days=7, weeks=4, months=3,
    ...                        firstweekday=SATURDAY, now=now))
    [datetime.date(1999, 1, 1),
     ...
     datetime.date(1999, 9, 30),
     datetime.date(1999, 10, 2),
     ...
     datetime.date(1999, 10, 31),
     datetime.date(1999, 11, 2),
     ...
     datetime.date(1999, 11, 30),
     datetime.date(1999, 12, 2),
     datetime.date(1999, 12, 3),
     datetime.date(1999, 12, 5),
     ...
     datetime.date(1999, 12, 10),
     datetime.date(1999, 12, 12),
     ...
     datetime.date(1999, 12, 17),
     datetime.date(1999, 12, 19),
     ...
     datetime.date(1999, 12, 24)]

Finally, if you need to rotate backups that have timestamps in
``datetime`` format, you can use the corresponding ``to_keep`` and
``to_delete`` functions::

    >>> now = datetime.datetime(1999, 12, 31, 23, 59, 59)
    >>> start_datetime = datetime.datetime(1999, 12, 31, 0, 0, 0)
    >>> end_datetime = datetime.datetime(1999, 12, 31, 23, 59, 59)
    >>> backups = [start_datetime + datetime.timedelta(seconds=i)
    ...            for i
    ...            in xrange((end_datetime - start_datetime).seconds + 1)]
    >>> backups
    [datetime.datetime(1999, 12, 31, 0, 0),
     datetime.datetime(1999, 12, 31, 0, 0, 1),
     datetime.datetime(1999, 12, 31, 0, 0, 2),
     ...
     datetime.datetime(1999, 12, 31, 23, 59, 58),
     datetime.datetime(1999, 12, 31, 23, 59, 59)]

    >>> from grandfatherson import to_keep
    >>> sorted(to_keep(backups, hours=2, minutes=10, seconds=10, now=now))
    [datetime.datetime(1999, 12, 31, 22, 0),
     datetime.datetime(1999, 12, 31, 23, 0),
     datetime.datetime(1999, 12, 31, 23, 50),
     ...
     datetime.datetime(1999, 12, 31, 23, 59),
     datetime.datetime(1999, 12, 31, 23, 59, 50),
     ...
     datetime.datetime(1999, 12, 31, 23, 59, 59)]

    >>> from grandfatherson import to_delete
    >>> sorted(to_delete(backups, hours=2, minutes=10, seconds=10, now=now))
    [datetime.datetime(1999, 12, 31, 0, 0),
     ...
     datetime.datetime(1999, 12, 31, 21, 59, 59),
     datetime.datetime(1999, 12, 31, 22, 0, 1),
     ...
     datetime.datetime(1999, 12, 31, 22, 59, 59),
     datetime.datetime(1999, 12, 31, 23, 0, 1),
     ...
     datetime.datetime(1999, 12, 31, 23, 49, 59),
     datetime.datetime(1999, 12, 31, 23, 50, 1),
     ...
     datetime.datetime(1999, 12, 31, 23, 58, 59),
     datetime.datetime(1999, 12, 31, 23, 59, 1),
     ...
     datetime.datetime(1999, 12, 31, 23, 59, 49)]
"""

from calendar import (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY,
                      SUNDAY)
from datetime import datetime, time
import os

from grandfatherson import filters

def to_keep(datetimes,
            years=0, months=0, weeks=0, days=0,
            hours=0, minutes=0, seconds=0,
            firstweekday=SATURDAY, now=None):
    """
    Return a set of datetimes that should be kept, out of ``datetimes``.

    Keeps up to ``years``, ``months``, ``weeks``, ``days``,
    ``hours``, ``minutes``, and ``seconds`` in the past.

    When keeping weeks, it prefers to keep ``firstweekday``, which
    defaults to Saturday.

    If ``now`` is None, it will base its calculations on
    ``datetime.datetime.now()``. Datetimes after this point will always be
    kept.
    """
    datetimes = set(datetimes)
    return (filters.Years.filter(datetimes, number=years, now=now) |
            filters.Months.filter(datetimes, number=months, now=now) |
            filters.Weeks.filter(datetimes, number=weeks,
                                 firstweekday=firstweekday, now=now) |
            filters.Days.filter(datetimes, number=days, now=now) |
            filters.Hours.filter(datetimes, number=hours, now=now) |
            filters.Minutes.filter(datetimes, number=minutes, now=now) |
            filters.Seconds.filter(datetimes, number=seconds, now=now))

def to_delete(datetimes,
              years=0, months=0, weeks=0, days=0,
              hours=0, minutes=0, seconds=0,
              firstweekday=SATURDAY, now=None):
    """
    Return a set of datetimes that should be deleted, out of ``datetimes``.

    See ``to_keep`` for a description of arguments.
    """
    datetimes = set(datetimes)
    return datetimes - to_keep(datetimes,
                               years=years, months=months,
                               weeks=weeks, days=days,
                               hours=hours, minutes=minutes, seconds=seconds,
                               firstweekday=firstweekday, now=now)

def dates_to_keep(dates,
                  years=0, months=0, weeks=0, days=0, firstweekday=SATURDAY,
                  now=None):
    """
    Return a set of dates that should be kept, out of ``dates``.

    See ``to_keep`` for a description of arguments.
    """
    datetimes = to_keep((datetime.combine(d, time()) for d in dates),
                        years=years, months=months, weeks=weeks, days=days,
                        hours=0, minutes=0, seconds=0,
                        firstweekday=firstweekday, now=now)
    return set(dt.date() for dt in datetimes)

def dates_to_delete(dates,
                    years=0, months=0, weeks=0, days=0, firstweekday=SATURDAY,
                    now=None):
    """
    Return a set of date that should be deleted, out of ``dates``.

    See ``to_keep`` for a description of arguments.
    """
    dates = set(dates)
    return dates - dates_to_keep(dates,
                                 years=years, months=months,
                                 weeks=weeks, days=days,
                                 firstweekday=firstweekday, now=now)
<|endoftext|>


<commit_before>"""
This module contains the functions used by Calculator program
to change infix notation into postfix notation
"""
import numbers
output = []
operation_stack = []

def op_precedence(operation):
    """Checks the precednece of an operations

    Args:
        operation (str): mathematical operator

    Renturns:
        int: Precednece of the operation
    """

    return {
            '(': 6,
            '^': 4,
            '*': 3,
            '/': 3,
            '-': 2,
            '+': 2,
    }[operation]

def assoc_is_left(operation):
    """Checks if an operations assocativity is left

    Args:
        Operator (str): Mathematical operator
    Returns:
        Boolean: True if Assocativity is left
    """

    return {
            '(': False,
            '^': False,
            '*': True,
            '/': True,
            '-': True,
            '+': True,
    }[operation]

def op_switch(token, top_of_op_stack):
    """Checks for the conditions to activate the shunt

    Args:
        token (str): incoming operator for tokens
        top_of_op_stack (str): Operator at the Top of the operation Stack
    Returns:
        Boolean: if conditions are met shuntingswitch is True
    """

    if top_of_op_stack != '(':
        if op_precedence(top_of_op_stack) > op_precedence(token):
            return True
        elif op_precedence(top_of_op_stack) == op_precedence(token) and \
                assoc_is_left(top_of_op_stack):
            return True
        else:
            return False
    else:
        return False

def shuntingyard(tokens):
    """Transforms infix equations to rpn equations

    Args:
        tokens (list): processed infix equation
    Returns:
        output (lists): rpn equation
    """

    for token in tokens:
        if token.replace('.','',1).isdigit():
            output.append(token)
        elif token in [ '^', '*', '/', '-', '+']:
            if operation_stack:
                while op_switch(token, operation_stack[-1]) and operation_stack:
                    output.append(operation_stack.pop())
            operation_stack.append(token)
        elif token == '(':
            operation_stack.append(token)
        elif token == ')':
            while operation_stack[-1] != '(':
                output.append(operation_stack.pop())
            operation_stack.pop()
    while operation_stack:
        output.append(operation_stack.pop())
    return output[:]
<commit_msg>Made changes to shuntingyard to use _is_number function<commit_after>"""
This module contains the functions used by Calculator program
to change infix notation into postfix notation
"""
from Calculator.__init__ import _is_number
output = []
operation_stack = []

def op_precedence(operation):
    """Checks the precednece of an operations

    Args:
        operation (str): mathematical operator

    Renturns:
        int: Precednece of the operation
    """

    return {
            '(': 6,
            '^': 4,
            '*': 3,
            '/': 3,
            '-': 2,
            '+': 2,
    }[operation]

def assoc_is_left(operation):
    """Checks if an operations assocativity is left

    Args:
        Operator (str): Mathematical operator
    Returns:
        Boolean: True if Assocativity is left
    """

    return {
            '(': False,
            '^': False,
            '*': True,
            '/': True,
            '-': True,
            '+': True,
    }[operation]

def op_switch(token, top_of_op_stack):
    """Checks for the conditions to activate the shunt

    Args:
        token (str): incoming operator for tokens
        top_of_op_stack (str): Operator at the Top of the operation Stack
    Returns:
        Boolean: if conditions are met shuntingswitch is True
    """

    if top_of_op_stack != '(':
        if op_precedence(top_of_op_stack) > op_precedence(token):
            return True
        elif op_precedence(top_of_op_stack) == op_precedence(token) and \
                assoc_is_left(top_of_op_stack):
            return True
        else:
            return False
    else:
        return False

def shuntingyard(tokens):
    """Transforms infix equations to rpn equations

    Args:
        tokens (list): processed infix equation
    Returns:
        output (lists): rpn equation
    """

    for token in tokens:
        if all([_is_number(char) for char in token]):
            output.append(token)
        elif token in [ '^', '*', '/', '-', '+']:
            if operation_stack:
                while op_switch(token, operation_stack[-1]) and operation_stack:
                    output.append(operation_stack.pop())
            operation_stack.append(token)
        elif token == '(':
            operation_stack.append(token)
        elif token == ')':
            while operation_stack[-1] != '(':
                output.append(operation_stack.pop())
            operation_stack.pop()
    while operation_stack:
        output.append(operation_stack.pop())
    return output[:]
<|endoftext|>


<commit_before>"""Top-level import of class PyGraphistry as "Graphistry". Used to connect to the Graphistry server and then create a base plotter."""

from __future__ import absolute_import
from __future__ import print_function
from future import standard_library
standard_library.install_aliases()
from builtins import object
import sys
import calendar
import time
import gzip
import io
import json
import requests
import numpy

from . import util

class PyGraphistry(object):
    api_key = None
    _tag = util.fingerprint()
    _dataset_prefix = 'PyGraphistry/'
    _hostname = 'localhost:3000'

    @staticmethod
    def register(key, server='proxy-labs.graphistry.com'):
        """API key registration and server selection

        Changing the key effects all derived Plotter instances.

        :param key: API key.
        :type key: String.
        :param server: URL of the visualization server.
        :type server: Optional string.
        :returns: None.
        :rtype: None.

        **Example: Standard**
                ::

                    import graphistry
                    graphistry.register(key="my api key")

        **Example: Developer**
                ::

                    import graphistry
                    graphistry.register('my api key', 'staging')

        """

        shortcuts = {'localhost': 'localhost:3000',
                     'staging': 'proxy-staging.graphistry.com',
                     'labs': 'proxy-labs.graphistry.com'}
        if server in shortcuts:
            PyGraphistry._hostname = shortcuts[server]
        else:
            PyGraphistry._hostname = server
        PyGraphistry.api_key = key.strip()
        PyGraphistry._check_key()

    @staticmethod
    def bind(node=None, source=None, destination=None,
             edge_title=None, edge_label=None, edge_color=None, edge_weight=None,
             point_title=None, point_label=None, point_color=None, point_size=None):
        """Create a base plotter.

        Typically called at start of a program. For parameters, see ``plotter.bind()`` .

        :returns: Plotter.
        :rtype: Plotter.

        **Example**

                ::

                    import graphistry
                    g = graphistry.bind()

        """

        from . import plotter
        return plotter.Plotter().bind(source, destination, node, \
                              edge_title, edge_label, edge_color, edge_weight, \
                              point_title, point_label, point_color, point_size)

    @staticmethod
    def nodes(nodes):
        from . import plotter
        return plotter.Plotter().nodes(nodes)

    @staticmethod
    def edges(edges):
        from . import plotter
        return plotter.Plotter().edges(edges)

    @staticmethod
    def graph(ig):
        from . import plotter
        return plotter.Plotter().graph(ig)

    @staticmethod
    def settings(height=None, url_params={}):
        from . import plotter
        return plotter.Plotter().settings(height, url_params)

    @staticmethod
    def _etl_url():
        return 'http://%s/etl' % PyGraphistry._hostname

    @staticmethod
    def _check_url():
        return 'http://%s/api/check' % PyGraphistry._hostname

    @staticmethod
    def _viz_url(dataset_name, url_params):
        splash_time = int(calendar.timegm(time.gmtime())) + 5
        extra = '&'.join([ k + '=' + str(v) for k,v in list(url_params.items())])
        pattern = 'http://%s/graph/graph.html?dataset=%s&usertag=%s&key=%s&splashAfter=%s&%s'
        return pattern % (PyGraphistry._hostname, dataset_name, PyGraphistry._tag,
                          PyGraphistry.api_key, splash_time, extra)

    @staticmethod
    def _etl(dataset):
        if PyGraphistry.api_key is None:
            raise ValueError('API key required')

        json_dataset = json.dumps(dataset, ensure_ascii=False, cls=NumpyJSONEncoder)
        headers = {'Content-Encoding': 'gzip', 'Content-Type': 'application/json'}
        params = {'usertag': PyGraphistry._tag, 'agent': 'pygraphistry', 'apiversion' : '1',
                  'agentversion': sys.modules['graphistry'].__version__,
                  'key': PyGraphistry.api_key}

        out_file = io.BytesIO()
        with gzip.GzipFile(fileobj=out_file, mode='w', compresslevel=9) as f:
            if sys.version_info < (3,0) and isinstance(json_dataset, str):
                f.write(json_dataset)
            else:
                f.write(json_dataset.encode('utf8'))

        size = len(out_file.getvalue()) / 1024
        if size >= 10 * 1024:
            print('Uploading %d kB. This may take a while...' % size)
        elif size > 100 * 1024:
            util.error('Dataset is too large (%d kB)!' % size)

        try:
            response = requests.post(PyGraphistry._etl_url(), out_file.getvalue(),
                                     headers=headers, params=params)
        except requests.exceptions.ConnectionError as e:
            raise ValueError('Connection Error:', e.message)
        except requests.exceptions.HTTPError as e:
            raise ValueError('HTTP Error:', e.message)

        jres = response.json()
        if jres['success'] is not True:
            raise ValueError('Server reported error:', jres['msg'])
        else:
            return jres['dataset']

    @staticmethod
    def _check_key():
        params = {'text': PyGraphistry.api_key}
        try:
            response = requests.get(PyGraphistry._check_url(), params=params)
            jres = response.json()
            if jres['success'] is not True:
                util.warn(jres['error'])
        except Exception as e:
            pass

register = PyGraphistry.register
bind = PyGraphistry.bind
edges = PyGraphistry.edges
nodes = PyGraphistry.nodes
graph = PyGraphistry.graph
settings = PyGraphistry.settings

class NumpyJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, numpy.ndarray) and obj.ndim == 1:
                return obj.tolist()
        elif isinstance(obj, numpy.generic):
            return obj.item()
        return json.JSONEncoder.default(self, obj)
<commit_msg>Allow up to 15 seconds after etl for loading viz with no splashscreen<commit_after>"""Top-level import of class PyGraphistry as "Graphistry". Used to connect to the Graphistry server and then create a base plotter."""

from __future__ import absolute_import
from __future__ import print_function
from future import standard_library
standard_library.install_aliases()
from builtins import object
import sys
import calendar
import time
import gzip
import io
import json
import requests
import numpy

from . import util

class PyGraphistry(object):
    api_key = None
    _tag = util.fingerprint()
    _dataset_prefix = 'PyGraphistry/'
    _hostname = 'localhost:3000'

    @staticmethod
    def register(key, server='proxy-labs.graphistry.com'):
        """API key registration and server selection

        Changing the key effects all derived Plotter instances.

        :param key: API key.
        :type key: String.
        :param server: URL of the visualization server.
        :type server: Optional string.
        :returns: None.
        :rtype: None.

        **Example: Standard**
                ::

                    import graphistry
                    graphistry.register(key="my api key")

        **Example: Developer**
                ::

                    import graphistry
                    graphistry.register('my api key', 'staging')

        """

        shortcuts = {'localhost': 'localhost:3000',
                     'staging': 'proxy-staging.graphistry.com',
                     'labs': 'proxy-labs.graphistry.com'}
        if server in shortcuts:
            PyGraphistry._hostname = shortcuts[server]
        else:
            PyGraphistry._hostname = server
        PyGraphistry.api_key = key.strip()
        PyGraphistry._check_key()

    @staticmethod
    def bind(node=None, source=None, destination=None,
             edge_title=None, edge_label=None, edge_color=None, edge_weight=None,
             point_title=None, point_label=None, point_color=None, point_size=None):
        """Create a base plotter.

        Typically called at start of a program. For parameters, see ``plotter.bind()`` .

        :returns: Plotter.
        :rtype: Plotter.

        **Example**

                ::

                    import graphistry
                    g = graphistry.bind()

        """

        from . import plotter
        return plotter.Plotter().bind(source, destination, node, \
                              edge_title, edge_label, edge_color, edge_weight, \
                              point_title, point_label, point_color, point_size)

    @staticmethod
    def nodes(nodes):
        from . import plotter
        return plotter.Plotter().nodes(nodes)

    @staticmethod
    def edges(edges):
        from . import plotter
        return plotter.Plotter().edges(edges)

    @staticmethod
    def graph(ig):
        from . import plotter
        return plotter.Plotter().graph(ig)

    @staticmethod
    def settings(height=None, url_params={}):
        from . import plotter
        return plotter.Plotter().settings(height, url_params)

    @staticmethod
    def _etl_url():
        return 'http://%s/etl' % PyGraphistry._hostname

    @staticmethod
    def _check_url():
        return 'http://%s/api/check' % PyGraphistry._hostname

    @staticmethod
    def _viz_url(dataset_name, url_params):
        splash_time = int(calendar.timegm(time.gmtime())) + 15
        extra = '&'.join([ k + '=' + str(v) for k,v in list(url_params.items())])
        pattern = 'http://%s/graph/graph.html?dataset=%s&usertag=%s&key=%s&splashAfter=%s&%s'
        return pattern % (PyGraphistry._hostname, dataset_name, PyGraphistry._tag,
                          PyGraphistry.api_key, splash_time, extra)

    @staticmethod
    def _etl(dataset):
        if PyGraphistry.api_key is None:
            raise ValueError('API key required')

        json_dataset = json.dumps(dataset, ensure_ascii=False, cls=NumpyJSONEncoder)
        headers = {'Content-Encoding': 'gzip', 'Content-Type': 'application/json'}
        params = {'usertag': PyGraphistry._tag, 'agent': 'pygraphistry', 'apiversion' : '1',
                  'agentversion': sys.modules['graphistry'].__version__,
                  'key': PyGraphistry.api_key}

        out_file = io.BytesIO()
        with gzip.GzipFile(fileobj=out_file, mode='w', compresslevel=9) as f:
            if sys.version_info < (3,0) and isinstance(json_dataset, str):
                f.write(json_dataset)
            else:
                f.write(json_dataset.encode('utf8'))

        size = len(out_file.getvalue()) / 1024
        if size >= 10 * 1024:
            print('Uploading %d kB. This may take a while...' % size)
        elif size > 100 * 1024:
            util.error('Dataset is too large (%d kB)!' % size)

        try:
            response = requests.post(PyGraphistry._etl_url(), out_file.getvalue(),
                                     headers=headers, params=params)
        except requests.exceptions.ConnectionError as e:
            raise ValueError('Connection Error:', e.message)
        except requests.exceptions.HTTPError as e:
            raise ValueError('HTTP Error:', e.message)

        jres = response.json()
        if jres['success'] is not True:
            raise ValueError('Server reported error:', jres['msg'])
        else:
            return jres['dataset']

    @staticmethod
    def _check_key():
        params = {'text': PyGraphistry.api_key}
        try:
            response = requests.get(PyGraphistry._check_url(), params=params)
            jres = response.json()
            if jres['success'] is not True:
                util.warn(jres['error'])
        except Exception as e:
            pass

register = PyGraphistry.register
bind = PyGraphistry.bind
edges = PyGraphistry.edges
nodes = PyGraphistry.nodes
graph = PyGraphistry.graph
settings = PyGraphistry.settings

class NumpyJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, numpy.ndarray) and obj.ndim == 1:
                return obj.tolist()
        elif isinstance(obj, numpy.generic):
            return obj.item()
        return json.JSONEncoder.default(self, obj)
<|endoftext|>


<commit_before>import django
from django.utils.translation import ugettext_lazy as _

DEBUG = False
TEMPLATE_DEBUG = True

ADMINS = ()

CONTACT_EMAIL = 'webmaster@sensiblewashington.org'

SENTRY_ADMINS = (
    ('Matthew Scott', 'matt@11craft.com'),
)

MANAGERS = SENTRY_ADMINS

SENTRY_CATCH_404_ERRORS = True

DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '5432',
    }
}

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Los_Angeles'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = '/media/'

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/admin/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = 'replace this value in a production environment'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
    'django.template.loaders.eggs.Loader',
)

MIDDLEWARE_CLASSES = (
    # 'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'cms.middleware.page.CurrentPageMiddleware',
    'cms.middleware.user.CurrentUserMiddleware',
    'cms.middleware.media.PlaceholderMediaMiddleware',
    'groups.middleware.GroupAwareMiddleware',
    'pagination.middleware.PaginationMiddleware',
    # 'django.middleware.cache.FetchFromCacheMiddleware',
)

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.request',
    'django.contrib.messages.context_processors.messages',

    'allauth.account.context_processors.account',

    'cms.context_processors.media',

    'sw.context_processors.team_membership',

    'zinnia.context_processors.media',
    'zinnia.context_processors.version',
)

# ==================================================================
# Static files

if django.VERSION < (1, 3):
    TEMPLATE_CONTEXT_PROCESSORS += (
        'staticfiles.context_processors.static_url',
    )
    STATICFILES_RESOLVERS = (
        'staticfiles.resolvers.AppDirectoriesResolver',
    )

ROOT_URLCONF = 'swproject.urls'

TEMPLATE_DIRS = (
    # We put all of our templates in apps, including the swtemplates app
    # for top-level templates.
)

if django.VERSION >= (1, 3):
    STATICFILES_URL = MEDIA_URL
else:
    STATIC_URL = MEDIA_URL

# =================================================================
# Tests

# These tests seem to cause problems on occasion.
TEST_EXCLUDE = (
    'allauth',
    'ghettoq',
    'reversion',
    'sentry',
    'zinnia',
)

TEST_RUNNER = 'swproject.testing.CustomTestSuiteRunner'

# =================================================================
# Cache

CACHE_BACKEND = 'locmem:///?max_entries=5000'

# ==================================================================
# url overrides

ABSOLUTE_URL_OVERRIDES = {
    'auth.user': lambda o: '/profiles/profile/%s/' % o.username,
}

# =================================================================
# auth

ACCOUNT_EMAIL_REQUIRED = False

LOGIN_REDIRECT_URL = '/'

AUTO_JOIN_GROUPS = [
    'wiki.editor',
]

# =================================================================
# django-cms

CMS_TEMPLATES = (
    ('cms/base.html', _('Default')),
)

LANGUAGES = (
    ('en', _('US English')),
)

LANGUAGE_CODE = 'en'

APPEND_SLASH = True

# ==================================================================
# zinnia

# TODO: Get a key for sensible washington.
# AKISMET_SECRET_KEY_API = '...'

ZINNIA_AKISMET_COMMENT = False

# from zinnia.xmlrpc import ZINNIA_XMLRPC_METHODS
# XMLRPC_METHODS = ZINNIA_XMLRPC_METHODS

ZINNIA_MEDIA_URL = '/media/zinnia/'

# ==================================================================
# comments

COMMENTS_APP = 'sw.custom_comments'

# ==================================================================
# wakawaka (wiki)

WAKAWAKA_REQUIRE_TEAM_ROLE = ('wiki', 'member')

WAKAWAKA_EDITOR_COLUMNS = 70

# This applies to URL matching only, not to parsing pages.
WAKAWAKA_SLUG_REGEX = r'(.*)'

# ==================================================================
# waka cms plugin

# The slug of the team to grab wiki content snippets from, or None
# to use the global wiki.
WAKACMSPLUGIN_TEAM_SLUG = 'webcontent'

# ==================================================================
# postmark, email

DEFAULT_FROM_EMAIL = 'Sensible Washington <webmaster@sensiblewashington.org>'
SERVER_EMAIL = 'Sensible Washington <webmaster@sensiblewashington.org>'

POSTMARK_API_KEY = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
POSTMARK_SENDER = DEFAULT_FROM_EMAIL
EMAIL_BACKEND = 'postmark.django_backend.EmailBackend'

EMAIL_CONFIRMATION_DAYS = 7

# ==================================================================
# emailfwd

EMAILFWD_VALID_DOMAINS = [
    ('sensiblewashington.org', '@sensiblewashington.org'),
]

EMAILFWD_DEFAULT_DOMAIN = 'sensiblewashington.org'

# ==================================================================
# Haystack (search)

HAYSTACK_SITECONF = 'swproject.search_sites'
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10
HAYSTACK_LIMIT_TO_REGISTERED_MODELS = False

# ==================================================================
# idios (profiles)

AUTH_PROFILE_MODULE = 'sw.Profile'

# ==================================================================

INSTALLED_APPS = (
    #
    # ORDER MATTERS.
    #
    # Media, templates
    'sw',
    #
    # Legacy URL redirection.
    'swlegacy',
    #
    # Included in Django
    'django.contrib.admin',
    'django.contrib.admindocs',
    'django.contrib.auth',
    'django.contrib.comments',
    'django.contrib.contenttypes',
    'django.contrib.gis',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles' if django.VERSION >= (1, 3) else 'staticfiles',
    #
    # Infrastructure
    'djcelery',
    'gunicorn',
    'south',
    #
    # Used by multiple apps
    'pagination',
    #
    # Sentry
    'indexer',
    'paging',
    'sentry',
    'sentry.client',
    #
    # Authentication
    'emailconfirmation',
    'uni_form',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.twitter',
    'allauth.openid',
    'allauth.facebook',
    #
    # django-cms master
    'cms',
    'cms.plugins.text',
    'cms.plugins.picture',
    'cms.plugins.link',
    'cms.plugins.file',
    'cms.plugins.snippet',
    'cms.plugins.googlemap',
    'mptt',
    'publisher',
    'menus',
    'reversion',
    #
    # zinnia
    'tagging',
    'zinnia',
    'zinnia.plugins',
    #
    # wakawaka (wiki)
    'wakawaka',
    'django_markup',
    'wakacmsplugin',
    #
    # django-voice (feedback)
    'djangovoice',
    'voting',
    'gravatar',
    #
    # Comment extensions
    'sw.custom_comments',
    #
    # Haystack (search)
    'haystack',
    #
    # email forwarding
    'emailfwd',
    #
    # idios (profiles)
    'idios',
    #
    # teams
    'teams',
    'groups',
    #
    # dashboard
    'dashboard',
)

import os
if os.environ.get('QUICK') == '1':
    # Disable schema-heavy apps for quicker test db setup.
    INSTALLED_APPS = list(INSTALLED_APPS)
    for app in [
        'cms',
        'cms.plugins.text',
        'cms.plugins.picture',
        'cms.plugins.link',
        'cms.plugins.file',
        'cms.plugins.snippet',
        'cms.plugins.googlemap',
        'sentry',
        'sentry.client',
        'wakacmsplugin',
        'zinnia',
        'zinnia.plugins',
        ]:
        INSTALLED_APPS.remove(app)
    INSTALLED_APPS = tuple(INSTALLED_APPS)
<commit_msg>Redirect to /teams/ on login<commit_after>import django
from django.utils.translation import ugettext_lazy as _

DEBUG = False
TEMPLATE_DEBUG = True

ADMINS = ()

CONTACT_EMAIL = 'webmaster@sensiblewashington.org'

SENTRY_ADMINS = (
    ('Matthew Scott', 'matt@11craft.com'),
)

MANAGERS = SENTRY_ADMINS

SENTRY_CATCH_404_ERRORS = True

DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '5432',
    }
}

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Los_Angeles'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = '/media/'

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/admin/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = 'replace this value in a production environment'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
    'django.template.loaders.eggs.Loader',
)

MIDDLEWARE_CLASSES = (
    # 'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'cms.middleware.page.CurrentPageMiddleware',
    'cms.middleware.user.CurrentUserMiddleware',
    'cms.middleware.media.PlaceholderMediaMiddleware',
    'groups.middleware.GroupAwareMiddleware',
    'pagination.middleware.PaginationMiddleware',
    # 'django.middleware.cache.FetchFromCacheMiddleware',
)

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.request',
    'django.contrib.messages.context_processors.messages',

    'allauth.account.context_processors.account',

    'cms.context_processors.media',

    'sw.context_processors.team_membership',

    'zinnia.context_processors.media',
    'zinnia.context_processors.version',
)

# ==================================================================
# Static files

if django.VERSION < (1, 3):
    TEMPLATE_CONTEXT_PROCESSORS += (
        'staticfiles.context_processors.static_url',
    )
    STATICFILES_RESOLVERS = (
        'staticfiles.resolvers.AppDirectoriesResolver',
    )

ROOT_URLCONF = 'swproject.urls'

TEMPLATE_DIRS = (
    # We put all of our templates in apps, including the swtemplates app
    # for top-level templates.
)

if django.VERSION >= (1, 3):
    STATICFILES_URL = MEDIA_URL
else:
    STATIC_URL = MEDIA_URL

# =================================================================
# Tests

# These tests seem to cause problems on occasion.
TEST_EXCLUDE = (
    'allauth',
    'ghettoq',
    'reversion',
    'sentry',
    'zinnia',
)

TEST_RUNNER = 'swproject.testing.CustomTestSuiteRunner'

# =================================================================
# Cache

CACHE_BACKEND = 'locmem:///?max_entries=5000'

# ==================================================================
# url overrides

ABSOLUTE_URL_OVERRIDES = {
    'auth.user': lambda o: '/profiles/profile/%s/' % o.username,
}

# =================================================================
# auth

ACCOUNT_EMAIL_REQUIRED = False

LOGIN_REDIRECT_URL = '/teams/'

AUTO_JOIN_GROUPS = [
    'wiki.editor',
]

# =================================================================
# django-cms

CMS_TEMPLATES = (
    ('cms/base.html', _('Default')),
)

LANGUAGES = (
    ('en', _('US English')),
)

LANGUAGE_CODE = 'en'

APPEND_SLASH = True

# ==================================================================
# zinnia

# TODO: Get a key for sensible washington.
# AKISMET_SECRET_KEY_API = '...'

ZINNIA_AKISMET_COMMENT = False

# from zinnia.xmlrpc import ZINNIA_XMLRPC_METHODS
# XMLRPC_METHODS = ZINNIA_XMLRPC_METHODS

ZINNIA_MEDIA_URL = '/media/zinnia/'

# ==================================================================
# comments

COMMENTS_APP = 'sw.custom_comments'

# ==================================================================
# wakawaka (wiki)

WAKAWAKA_REQUIRE_TEAM_ROLE = ('wiki', 'member')

WAKAWAKA_EDITOR_COLUMNS = 70

# This applies to URL matching only, not to parsing pages.
WAKAWAKA_SLUG_REGEX = r'(.*)'

# ==================================================================
# waka cms plugin

# The slug of the team to grab wiki content snippets from, or None
# to use the global wiki.
WAKACMSPLUGIN_TEAM_SLUG = 'webcontent'

# ==================================================================
# postmark, email

DEFAULT_FROM_EMAIL = 'Sensible Washington <webmaster@sensiblewashington.org>'
SERVER_EMAIL = 'Sensible Washington <webmaster@sensiblewashington.org>'

POSTMARK_API_KEY = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
POSTMARK_SENDER = DEFAULT_FROM_EMAIL
EMAIL_BACKEND = 'postmark.django_backend.EmailBackend'

EMAIL_CONFIRMATION_DAYS = 7

# ==================================================================
# emailfwd

EMAILFWD_VALID_DOMAINS = [
    ('sensiblewashington.org', '@sensiblewashington.org'),
]

EMAILFWD_DEFAULT_DOMAIN = 'sensiblewashington.org'

# ==================================================================
# Haystack (search)

HAYSTACK_SITECONF = 'swproject.search_sites'
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10
HAYSTACK_LIMIT_TO_REGISTERED_MODELS = False

# ==================================================================
# idios (profiles)

AUTH_PROFILE_MODULE = 'sw.Profile'

# ==================================================================

INSTALLED_APPS = (
    #
    # ORDER MATTERS.
    #
    # Media, templates
    'sw',
    #
    # Legacy URL redirection.
    'swlegacy',
    #
    # Included in Django
    'django.contrib.admin',
    'django.contrib.admindocs',
    'django.contrib.auth',
    'django.contrib.comments',
    'django.contrib.contenttypes',
    'django.contrib.gis',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles' if django.VERSION >= (1, 3) else 'staticfiles',
    #
    # Infrastructure
    'djcelery',
    'gunicorn',
    'south',
    #
    # Used by multiple apps
    'pagination',
    #
    # Sentry
    'indexer',
    'paging',
    'sentry',
    'sentry.client',
    #
    # Authentication
    'emailconfirmation',
    'uni_form',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.twitter',
    'allauth.openid',
    'allauth.facebook',
    #
    # django-cms master
    'cms',
    'cms.plugins.text',
    'cms.plugins.picture',
    'cms.plugins.link',
    'cms.plugins.file',
    'cms.plugins.snippet',
    'cms.plugins.googlemap',
    'mptt',
    'publisher',
    'menus',
    'reversion',
    #
    # zinnia
    'tagging',
    'zinnia',
    'zinnia.plugins',
    #
    # wakawaka (wiki)
    'wakawaka',
    'django_markup',
    'wakacmsplugin',
    #
    # django-voice (feedback)
    'djangovoice',
    'voting',
    'gravatar',
    #
    # Comment extensions
    'sw.custom_comments',
    #
    # Haystack (search)
    'haystack',
    #
    # email forwarding
    'emailfwd',
    #
    # idios (profiles)
    'idios',
    #
    # teams
    'teams',
    'groups',
    #
    # dashboard
    'dashboard',
)

import os
if os.environ.get('QUICK') == '1':
    # Disable schema-heavy apps for quicker test db setup.
    INSTALLED_APPS = list(INSTALLED_APPS)
    for app in [
        'cms',
        'cms.plugins.text',
        'cms.plugins.picture',
        'cms.plugins.link',
        'cms.plugins.file',
        'cms.plugins.snippet',
        'cms.plugins.googlemap',
        'sentry',
        'sentry.client',
        'wakacmsplugin',
        'zinnia',
        'zinnia.plugins',
        ]:
        INSTALLED_APPS.remove(app)
    INSTALLED_APPS = tuple(INSTALLED_APPS)
<|endoftext|>