<commit_before>'''
Tourney.py
Runs a tournament of continuous pairs.
Dealer class and other game mechanics imported from pairsClasses.
Strategies to play in the tournament need to be imported, initialized,
and passed to tournament function.
'''
from __future__ import division
from itertools import chain, combinations
import pairsClasses as p
from random import shuffle
try:
    import numpy as np
    numpy = True
except ImportError:
    print("The module numpy was not found.  Probabilities will not be reported in results.")
    numpy = False

# Specify strategies to import here
from strategies.chrisStrategies import SmartRatio
from strategies.DannisStrategy import NoCardKnowledge
from strategies.michaelStrategies import OverThinker
from strategies.alexStrategies import CruelFoldNoCount
from strategies.brianStrategies import noPeek
#from strategies.chrisStrategies import Interactive

# Initalize strategies in dict
strategies = {"Chris": SmartRatio(1.1),
              "Alex": CruelFoldNoCount(),
              "Danni": NoCardKnowledge(4),
              "Brian": noPeek(),
              "Michael": OverThinker(),
#              "Me": Interactive()
              }

for key, value in strategies.items():
    value.tourney_key = key

class Tourney:

    def __init__(self, strategies, games = 50000, check = 100, prob = 0.95, prior = 500):
        self.strats = strategies
        self.n = len(strategies)
        self.games = games
        self.check = check
        self.prob = prob
        self.prior = prior
        self.lost = dict.fromkeys(list(strategies.keys()), 0)
        self.early = False
        self.interactive = False

    def play(self):
        for g in range(self.games):
            d = p.Dealer(self.n, verbose = False, standard = True, calamity = False)
            keys = list(self.strats.values())
            shuffle(keys)
            for j, s in enumerate(keys):
                d.gameState.players[j].strategy = s
            # play a game and get the key of the losing strategy
            loser = d.gameState.players[d.play()].strategy.tourney_key
            self.lost[loser] += 1
            if not (g+1) % self.check:
                self._summary(g+1)
            if self.interactive:
                print('%s lost.' % (loser))
                input('Press Enter to continue.')
            if self.early:
                break
        return self.lost

    def _summary(self, g):
        print("--------------------------------")
        print("Games Played:\t" + str(g))
        print("\n\tLost\tPercent")
        for key in self.strats:
            print(key + "\t" + str(self.lost[key]) + "\t" + '%.2f' % (self.lost[key] / g))

        if numpy:
            self._report_probs()

    def _report_probs(self):
            prior = np.repeat(self.prior, self.n)
            posterior = prior + np.array(list(self.lost.values()))
            keys = list(self.lost.keys())
            N = 10000
            draws = np.random.dirichlet(posterior, N)
            best = np.bincount(np.argmin(draws, axis = 1), minlength = self.n) / N
            worst = np.bincount(np.argmax(draws, axis = 1), minlength = self.n) / N

            print("\n\tP(best)\tP(worst)")
            for i, key in enumerate(self.strats):
                print(key + "\t" + '%.2f' % best[keys.index(key)] + "\t" +
                        '%.2f' % worst[keys.index(key)])
            if max(best) > self.prob and max(worst) > self.prob:
                print("Stopping early due to high probabilities of best and worst."
                        "(Threshold set to " + str(self.prob) + ")")
                self.early = True

class GrandTourney:

    def __init__(self, strategies, games = 100, check = 500, prob = 0.95, prior = 500):
        self.strats = strategies
        self.n = len(strategies)
        self.games = games
        self.check = check
        self.prob = prob
        self.prior = prior
        self.results = {}
        for strat in self.strats:
            self.strats[strat].gt_indices = {}
            for i in range(2, self.n+1):
                self.strats[strat].gt_indices[i] = []
            self.strats[strat].gt_games = 0
            self.strats[strat].gt_losses = 0

    def _create_subsets(self):
        keys = list(self.strats.keys())
        return chain.from_iterable( combinations(keys, n) for n in range(2, len(keys)+1) )

    def play(self, stop = True):
        subsets = self._create_subsets()
        for subset in subsets:
            self.results[subset] = Tourney({s:self.strats[s] for s in self.strats if s in subset}, self.games, self.check, self.prob, self.prior).play()
            if stop:
                input("Game Ended")
        self._grand_tourney_report()

    def _tourney_report(self, results):
        print('\t'.join(["Player","Losses","Percent","Index"]))
        total = sum(results.values())
        for key in results:
            losses = results[key]
            percent = (results[key] / total)
            index = (results[key] / total * len(results))
            self.strats[key].gt_games += total
            self.strats[key].gt_losses += losses
            self.strats[key].gt_indices[len(results)].append(index)
            print('\t'.join([key, str(losses), '%.2f' % percent, '%.2f' % index]))
        print('\n')

    def _grand_tourney_report(self):
        print("--------------------------------------------")
        print("|          Grand Tourney Results           |")
        print("--------------------------------------------")
        print("Total Tournaments Played: " + str(len(self.results)))

        for i in range(2, self.n+1):
            print("--------------------------------------------")
            print(str(i) + "-Player Tournaments:")
            for result in self.results.values():
                if len(result) == i:
                    self._tourney_report(result)

        print("--------------------------------------------")
        print("|              Final Indices               |")
        print("--------------------------------------------")

        overall = {}
        for key in self.strats:
            strat = self.strats[key]
            strat.gt_means = []
            for i in range(2, self.n+1):
                strat.gt_means.append( sum(strat.gt_indices[i]) / len(strat.gt_indices[i]) )
            overall[key] = sum(strat.gt_means) / len(strat.gt_means)
            strat.gt_means.append(overall[key])
            for i in range(len(strat.gt_means)):
                strat.gt_means[i] = '%.2f' % strat.gt_means[i]

        order = sorted(overall, key=overall.get)
        print('\t'.join(['Player'] + [str(i) for i in range(2, self.n+1)] + ['Overall']))
        for s in order:
            print(s + '\t' + '\t'.join(self.strats[s].gt_means))

if __name__ == "__main__":
    log = False
    if(log):
        import sys

        class Tee(object):
            def __init__(self, *files):
                self.files = files
            def write(self, obj):
                for f in self.files:
                    f.write(obj)

        f = open('tourney_log.txt', 'w')
        original = sys.stdout
        sys.stdout = Tee(sys.stdout, f)

    tourney = Tourney(strategies, games = 10000, check = 100)
    tourney.play()

    if(log):
        f.close()
        sys.stdout = original
<commit_msg>Improve result formatting and reduce line length<commit_after>'''
Tourney.py
Runs a tournament of continuous pairs.
Dealer class and other game mechanics imported from pairsClasses.
Strategies to play in the tournament need to be imported, initialized,
and passed to tournament function.
'''
from __future__ import division
from itertools import chain, combinations
import pairsClasses as p
from random import shuffle
try:
    import numpy as np
    numpy = True
except ImportError:
    print("The module numpy was not found."
          "Probabilities will not be reported in results.")
    numpy = False

# Specify strategies to import here
from strategies.chrisStrategies import SmartRatio
from strategies.DannisStrategy import NoCardKnowledge
from strategies.michaelStrategies import OverThinker
from strategies.alexStrategies import CruelFoldNoCount
from strategies.brianStrategies import noPeek
#from strategies.chrisStrategies import Interactive

# Initalize strategies in dict
strategies = {"Chris": SmartRatio(1.1),
              "Alex": CruelFoldNoCount(),
              "Danni": NoCardKnowledge(4),
              "Brian": noPeek(),
              "Michael": OverThinker(),
#              "Me": Interactive()
              }

for key, value in strategies.items():
    value.tourney_key = key

class Tourney:

    def __init__(self, strategies, games = 50000, check = 100, prob = 0.95,
                 prior = 500):
        self.strats = strategies
        self.n = len(strategies)
        self.games = games
        self.check = check
        self.prob = prob
        self.prior = prior
        self.lost = dict.fromkeys(list(strategies.keys()), 0)
        self.early = False
        self.interactive = False
        self.nw = max(len(k) for k in strategies.keys()) + 5
        self.rw = 10

    def play(self):
        for g in range(self.games):
            d = p.Dealer(self.n, verbose = False, standard = True,
                         calamity = False)
            keys = list(self.strats.values())
            shuffle(keys)
            for j, s in enumerate(keys):
                d.gameState.players[j].strategy = s
            # play a game and get the key of the losing strategy
            loser = d.gameState.players[d.play()].strategy.tourney_key
            self.lost[loser] += 1
            if not (g+1) % self.check:
                self._summary(g+1)
            if self.interactive:
                print('%s lost.' % (loser))
                input('Press Enter to continue.')
            if self.early:
                break
        return self.lost

    def _summary(self, g):
        print("--------------------------------")
        print("Games Played:\t" + str(g) + "\n")
        row = "{:<%d}{:<%d}{:<%d}" % (self.nw, self.rw, self.rw)
        print(row.format("", "Lost", "Percent"))
        for key in self.strats:
            print(row.format(key, str(self.lost[key]),
                             '%.2f' % (self.lost[key] / g)))

        if numpy:
            self._report_probs()

    def _report_probs(self):
            prior = np.repeat(self.prior, self.n)
            posterior = prior + np.array(list(self.lost.values()))
            keys = list(self.lost.keys())
            N = 10000
            draws = np.random.dirichlet(posterior, N)
            best = np.bincount(np.argmin(draws, axis = 1),
                               minlength = self.n) / N
            worst = np.bincount(np.argmax(draws, axis = 1),
                                minlength = self.n) / N

            print()
            row = "{:<%d}{:<%d}{:<%d}" % (self.nw, self.rw, self.rw)
            print(row.format("", "P(best)", "P(worst)"))
            for i, key in enumerate(self.strats):
                print(row.format(key,'%.2f' % best[keys.index(key)],
                                 '%.2f' % worst[keys.index(key)]))
            if max(best) > self.prob and max(worst) > self.prob:
                print("Stopping early due to high probabilities"
                      "of best and worst. (Threshold set to %s)" %
                      str(self.prob))
                self.early = True

class GrandTourney:

    def __init__(self, strategies, games = 100, check = 500, prob = 0.95,
                 prior = 500):
        self.strats = strategies
        self.n = len(strategies)
        self.games = games
        self.check = check
        self.prob = prob
        self.prior = prior
        self.results = {}
        for strat in self.strats:
            self.strats[strat].gt_indices = {}
            for i in range(2, self.n+1):
                self.strats[strat].gt_indices[i] = []
            self.strats[strat].gt_games = 0
            self.strats[strat].gt_losses = 0
        self.nw = max(len(name) for name in self.strats) + 5
        self.rw = 10

    def _create_subsets(self):
        keys = list(self.strats.keys())
        return chain.from_iterable(combinations(keys, n)
                                   for n in range(2, len(keys)+1))

    def play(self, stop = True):
        subsets = self._create_subsets()
        for subset in subsets:
            self.results[subset] = Tourney({s:self.strats[s]
                for s in self.strats if s in subset},
                self.games, self.check, self.prob, self.prior).play()
            if stop:
                input("Tourney Ended")
        self._grand_tourney_report()

    def _tourney_report(self, results):
        row = "{:<%d}"*4 % (self.nw, self.rw, self.rw, self.rw)
        print(row.format("","Losses","Percent","Index"))
        total = sum(results.values())
        for key in results:
            losses = results[key]
            percent = (results[key] / total)
            index = (results[key] / total * len(results))
            self.strats[key].gt_games += total
            self.strats[key].gt_losses += losses
            self.strats[key].gt_indices[len(results)].append(index)
            print(row.format(key, str(losses), '%.2f' % percent,
                             '%.2f' % index))
        print('\n')

    def _grand_tourney_report(self):
        print("-------------------------------------------------------------")
        print("|                    Grand Tourney Results                  |")
        print("-------------------------------------------------------------")
        print("Total Tournaments Played: " + str(len(self.results)))

        for i in range(2, self.n+1):
            print("--------------------------------------------")
            print(str(i) + "-Player Tournaments:")
            for result in self.results.values():
                if len(result) == i:
                    self._tourney_report(result)

        print("-------------------------------------------------------------")
        print("|                       Final Indices                       |")
        print("-------------------------------------------------------------")

        overall = {}
        row = "{:<%d}"*4 % (self.nw, self.rw, self.rw, self.rw)
        for key in self.strats:
            strat = self.strats[key]
            strat.gt_means = []
            for i in range(2, self.n+1):
                strat.gt_means.append(sum(strat.gt_indices[i]) /
                                      len(strat.gt_indices[i]))
            overall[key] = sum(strat.gt_means) / len(strat.gt_means)
            strat.gt_means.append(overall[key])
            for i in range(len(strat.gt_means)):
                strat.gt_means[i] = '%.2f' % strat.gt_means[i]

        order = sorted(overall, key=overall.get)
        lengths = tuple([self.nw] + [self.rw] * self.n)
        row = "{:<%d}"*(self.n+1) % lengths
        headers = tuple(['Player'] + [str(i) for i in range(2, self.n+1)] +
                        ['Overall'])
        print(row.format(*headers))
        for s in order:
            print(row.format(*tuple([s] + self.strats[s].gt_means)))

if __name__ == "__main__":
    log = False
    if(log):
        import sys

        class Tee(object):
            def __init__(self, *files):
                self.files = files
            def write(self, obj):
                for f in self.files:
                    f.write(obj)

        f = open('tourney_log.txt', 'w')
        original = sys.stdout
        sys.stdout = Tee(sys.stdout, f)

    tourney = GrandTourney(strategies, games = 10, check = 10)
    tourney.play()

    if(log):
        f.close()
        sys.stdout = original
<|endoftext|>


<commit_before># Copyright (c) 2014, Salesforce.com, Inc.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# - Neither the name of Salesforce.com nor the names of its contributors
#   may be used to endorse or promote products derived from this
#   software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import numpy
from numpy import pi
import scipy.stats
from scipy.special import gamma
from itertools import izip
from collections import defaultdict

def scores_to_probs(scores):
    scores = numpy.array(scores)
    scores -= scores.max()
    probs = numpy.exp(scores, out=scores)
    probs /= probs.sum()
    return probs

def score_to_empirical_kl(score, count):
    """
    Convert total log score to KL( empirical || model ),
    where the empirical pdf is uniform over `count` datapoints.
    """
    count = float(count)
    return -score / count - numpy.log(count)

def print_histogram(probs, counts):
    WIDTH = 60.0
    max_count = max(counts)
    print '{: >8} {: >8}'.format('Prob', 'Count')
    for prob, count in sorted(zip(probs, counts), reverse=True):
        width = int(round(WIDTH * count / max_count))
        print '{: >8.3f} {: >8d} {}'.format(prob, count, '-' * width)

def multinomial_goodness_of_fit(
        probs,
        counts,
        total_count,
        truncated=False,
        plot=False):
    """
    Pearson's chi^2 test, on possibly truncated data.
    http://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test

    Returns:
        p-value of truncated multinomial sample.
    """
    assert len(probs) == len(counts)
    assert truncated or total_count == sum(counts)
    chi_squared = 0
    dof = 0
    if plot:
        print_histogram(probs, counts)
    for p, c in izip(probs, counts):
        if p == 1:
            return 1 if c == total_count else 0
        assert p < 1, 'bad probability: %g' % p
        if p > 0:
            mean = total_count * p
            variance = total_count * p * (1 - p)
            assert variance > 1,\
                'WARNING goodness of fit is inaccurate; use more samples'
            chi_squared += (c - mean) ** 2 / variance
            dof += 1
        else:
            print 'WARNING zero probability in goodness-of-fit test'
            if c > 0:
                return float('inf')

    if not truncated:
        dof -= 1

    survival = scipy.stats.chi2.sf(chi_squared, dof)
    return survival

def unif01_goodness_of_fit(samples, plot=False):
    """
    Bin uniformly distributed samples and apply Pearson's chi^2 test.
    """
    samples = numpy.array(samples, dtype=float)
    assert samples.min() >= 0.0
    assert samples.max() <= 1.0
    bin_count = int(round(len(samples) ** 0.333))
    assert bin_count >= 7, 'WARNING imprecise test, use more samples'
    probs = numpy.ones(bin_count, dtype=numpy.float) / bin_count
    counts = numpy.zeros(bin_count, dtype=numpy.int)
    for sample in samples:
        counts[min(bin_count - 1, int(bin_count * sample))] += 1
    return multinomial_goodness_of_fit(probs, counts, len(samples), plot=plot)

def exp_goodness_of_fit(samples, plot, normalized=True, return_dict=False):
    """
    Transform exponentially distribued samples to unif01 distribution
    and assess goodness of fit via binned Pearson's chi^2 test.

    Inputs:
        samples - a list of real-valued samples from a candidate distribution
    """
    result = {}
    if not normalized:
        result['norm'] = numpy.mean(samples)
        samples /= result['norm']
    unif01_samples = numpy.exp(-samples)
    result['gof'] = unif01_goodness_of_fit(unif01_samples, plot=plot)
    return result if return_dict else result['gof']

def density_goodness_of_fit(
        samples,
        probs,
        plot=False,
        normalized=True,
        return_dict=False):
    """
    Transform arbitrary continuous samples to unif01 distribution
    and assess goodness of fit via binned Pearson's chi^2 test.

    Inputs:
        samples - a list of real-valued samples from a distribution
        probs - a list of probability densities evaluated at those samples
    """
    assert len(samples) == len(probs)
    assert len(samples) > 100, 'WARNING imprecision; use more samples'
    pairs = zip(samples, probs)
    pairs.sort()
    samples = numpy.array([x for x, p in pairs])
    probs = numpy.array([p for x, p in pairs])
    density = len(samples) * numpy.sqrt(probs[1:] * probs[:-1])
    gaps = samples[1:] - samples[:-1]
    exp_samples = density * gaps
    return exp_goodness_of_fit(exp_samples, plot, normalized, return_dict)

def volume_of_sphere(dim, radius):
    assert isinstance(dim, (int, long))
    return radius ** dim * pi ** (0.5 * dim) / gamma(0.5 * dim + 1)

def vector_density_goodness_of_fit(
        samples,
        probs,
        plot=False,
        normalized=True,
        return_dict=False):
    """
    Transform arbitrary multivariate continuous samples
    to unif01 distribution via nearest neighbor distribution [1,2,3]
    and assess goodness of fit via binned Pearson's chi^2 test.

    [1] http://projecteuclid.org/download/pdf_1/euclid.aop/1176993668
    [2] http://arxiv.org/pdf/1006.3019v2.pdf
    [3] http://en.wikipedia.org/wiki/Nearest_neighbour_distribution

    Inputs:
        samples - a list of real-vector-valued samples from a distribution
        probs - a list of probability densities evaluated at those samples
    """
    from sklearn.neighbors import NearestNeighbors
    assert samples
    assert len(samples) == len(probs)
    dim = len(samples[0])
    assert dim
    assert len(samples) > 1000 * dim, 'WARNING imprecision; use more samples'
    if not hasattr(samples[0], '__iter__'):
        samples = numpy.array([samples]).T
    neighbors = NearestNeighbors(n_neighbors=2).fit(samples)
    distances, indices = neighbors.kneighbors(samples)
    radii = distances[:, 1]
    density = len(samples) * numpy.array(probs)
    volume = volume_of_sphere(dim, radii)
    exp_samples = density * volume
    return exp_goodness_of_fit(exp_samples, plot, normalized, return_dict)

def auto_density_goodness_of_fit(
        samples,
        probs,
        plot=False,
        normalized=True,
        return_dict=False):
    assert samples
    if len(samples[0]) == 1:
        fun = density_goodness_of_fit
    else:
        fun = vector_density_goodness_of_fit
    return fun(samples, probs, plot, normalized, return_dict)

def discrete_goodness_of_fit(
        samples,
        probs_dict,
        truncate_beyond=8,
        plot=False,
        normalized=True):
    """
    Transform arbitrary discrete data to multinomial
    and assess goodness of fit via Pearson's chi^2 test.
    """
    if not normalized:
        norm = sum(probs_dict.itervalues())
        probs_dict = {i: p / norm for i, p in probs_dict.iteritems()}
    counts = defaultdict(lambda: 0)
    for sample in samples:
        assert sample in probs_dict
        counts[sample] += 1
    items = [(prob, counts.get(i, 0)) for i, prob in probs_dict.iteritems()]
    items.sort(reverse=True)
    truncated = (truncate_beyond and truncate_beyond < len(items))
    if truncated:
        items = items[:truncate_beyond]
    probs = [prob for prob, count in items]
    counts = [count for prob, count in items]
    assert sum(counts) > 100, 'WARNING imprecision; use more samples'
    return multinomial_goodness_of_fit(
        probs,
        counts,
        len(samples),
        truncated=truncated,
        plot=plot)

NoneType = type(None)

def split_discrete_continuous(data):
    """
    Convert arbitrary data to a pair `(discrete, continuous)`
    where `discrete` is hashable and `continuous` is a list of floats.
    """
    if isinstance(data, (NoneType, bool, int, long, basestring)):
        return data, []
    elif isinstance(data, (float, numpy.float32, numpy.float64)):
        return None, [data]
    elif isinstance(data, (tuple, list)):
        discrete = []
        continuous = []
        for part in data:
            d, c = split_discrete_continuous(part)
            discrete.append(d)
            continuous += c
        return tuple(discrete), continuous
    elif isinstance(data, numpy.ndarray):
        assert data.dtype in [numpy.float64, numpy.float32]
        return (None,) * len(data), map(float, data)
    else:
        raise TypeError(
            'split_discrete_continuous does not accept {} of type {}'.format(
                repr(data), str(type(data))))

def mixed_density_goodness_of_fit(
        samples,
        scores,
        plot=False,
        normalized=True):
    """
    Test general mixed discrete+continuous datatypes by
    (1) testing the continuous part conditioned on each discrete value, and
    (2) testing the discrete part marginalizing over the continuous part.

    Inputs:
        samples - a list of real-vector-valued samples from a distribution
        probs - a list of probability densities evaluated at those samples
    Returns:
        result['gof'] - a goodness of fit statistic in [0,1]
        result['norm'] - the empirical norm (if normalized=False)
    """
    assert samples
    discrete_samples = []
    strata = defaultdict(lambda: ([], []))
    for sample, score in izip(samples, scores):
        d, c = split_discrete_continuous(sample)
        discrete_samples.append(d)
        samples, scores = strata[d]
        samples.append(c)
        scores.append(score)

    # Continuous part
    gofs = []
    discrete_probs = {}
    for key, (samples, scores) in strata.iteritems():
        if len(samples[0]) == 1:
            discrete_probs[key] = numpy.exp(scores[0])
        else:
            result = auto_density_goodness_of_fit(
                samples,
                scores,
                plot=plot,
                normalized=False,
                return_dict=True)
            gofs.append(result['gof'])
            discrete_probs[key] = result['norm']

    # Discrete part
    if len(strata) > 1:
        gofs.append(discrete_goodness_of_fit(
            discrete_samples,
            discrete_probs,
            plot,
            normalized))

    return min(gofs)

def bin_samples(samples, k=10, support=[]):
    """
    Bins a collection of univariate samples into k bins of equal
    fill via the empirical cdf, to be used in goodness of fit testing.

    Returns
    counts : array k x 1
    bin_ranges : arrary k x 2

    each count is the number of samples in [bin_min, bin_max)
    except for the last bin which is [bin_min, bin_max]

    list partitioning algorithm adapted from Mark Dickinson:
    http://stackoverflow.com/questions/2659900
    """
    samples = sorted(samples)

    N = len(samples)
    q, r = divmod(N, k)
    # We need to distribute the remainder relatively evenly;
    # tests will be inaccurate if we have small bins at the end.
    indices = [i * q + min(r, i) for i in range(k + 1)]
    bins = [samples[indices[i]: indices[i + 1]] for i in range(k)]
    bin_ranges = []
    counts = []
    for i in range(k):
        bin_min = bins[i][0]
        try:
            bin_max = bins[i + 1][0]
        except IndexError:
            bin_max = bins[i][-1]
        bin_ranges.append([bin_min, bin_max])
        counts.append(len(bins[i]))
    if support:
        bin_ranges[0][0] = support[0]
        bin_ranges[-1][1] = support[1]
    return numpy.array(counts), numpy.array(bin_ranges)

def histogram(samples, bin_count=None):
    if bin_count is None:
        bin_count = numpy.max(samples) + 1
    v = numpy.zeros(bin_count, dtype=int)
    for sample in samples:
        v[sample] += 1
    return v
<commit_msg>Fix normalization bug in mixed_density_goodness_of_fit<commit_after># Copyright (c) 2014, Salesforce.com, Inc.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# - Neither the name of Salesforce.com nor the names of its contributors
#   may be used to endorse or promote products derived from this
#   software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import numpy
from numpy import pi
import scipy.stats
from scipy.special import gamma
from itertools import izip
from collections import defaultdict

def scores_to_probs(scores):
    scores = numpy.array(scores)
    scores -= scores.max()
    probs = numpy.exp(scores, out=scores)
    probs /= probs.sum()
    return probs

def score_to_empirical_kl(score, count):
    """
    Convert total log score to KL( empirical || model ),
    where the empirical pdf is uniform over `count` datapoints.
    """
    count = float(count)
    return -score / count - numpy.log(count)

def print_histogram(probs, counts):
    WIDTH = 60.0
    max_count = max(counts)
    print '{: >8} {: >8}'.format('Prob', 'Count')
    for prob, count in sorted(zip(probs, counts), reverse=True):
        width = int(round(WIDTH * count / max_count))
        print '{: >8.3f} {: >8d} {}'.format(prob, count, '-' * width)

def multinomial_goodness_of_fit(
        probs,
        counts,
        total_count,
        truncated=False,
        plot=False):
    """
    Pearson's chi^2 test, on possibly truncated data.
    http://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test

    Returns:
        p-value of truncated multinomial sample.
    """
    assert len(probs) == len(counts)
    assert truncated or total_count == sum(counts)
    chi_squared = 0
    dof = 0
    if plot:
        print_histogram(probs, counts)
    for p, c in izip(probs, counts):
        if p == 1:
            return 1 if c == total_count else 0
        assert p < 1, 'bad probability: %g' % p
        if p > 0:
            mean = total_count * p
            variance = total_count * p * (1 - p)
            assert variance > 1,\
                'WARNING goodness of fit is inaccurate; use more samples'
            chi_squared += (c - mean) ** 2 / variance
            dof += 1
        else:
            print 'WARNING zero probability in goodness-of-fit test'
            if c > 0:
                return float('inf')

    if not truncated:
        dof -= 1

    survival = scipy.stats.chi2.sf(chi_squared, dof)
    return survival

def unif01_goodness_of_fit(samples, plot=False):
    """
    Bin uniformly distributed samples and apply Pearson's chi^2 test.
    """
    samples = numpy.array(samples, dtype=float)
    assert samples.min() >= 0.0
    assert samples.max() <= 1.0
    bin_count = int(round(len(samples) ** 0.333))
    assert bin_count >= 7, 'WARNING imprecise test, use more samples'
    probs = numpy.ones(bin_count, dtype=numpy.float) / bin_count
    counts = numpy.zeros(bin_count, dtype=numpy.int)
    for sample in samples:
        counts[min(bin_count - 1, int(bin_count * sample))] += 1
    return multinomial_goodness_of_fit(probs, counts, len(samples), plot=plot)

def exp_goodness_of_fit(samples, plot, normalized=True, return_dict=False):
    """
    Transform exponentially distribued samples to unif01 distribution
    and assess goodness of fit via binned Pearson's chi^2 test.

    Inputs:
        samples - a list of real-valued samples from a candidate distribution
    """
    result = {}
    if not normalized:
        result['norm'] = numpy.mean(samples)
        samples /= result['norm']
    unif01_samples = numpy.exp(-samples)
    result['gof'] = unif01_goodness_of_fit(unif01_samples, plot=plot)
    return result if return_dict else result['gof']

def density_goodness_of_fit(
        samples,
        probs,
        plot=False,
        normalized=True,
        return_dict=False):
    """
    Transform arbitrary continuous samples to unif01 distribution
    and assess goodness of fit via binned Pearson's chi^2 test.

    Inputs:
        samples - a list of real-valued samples from a distribution
        probs - a list of probability densities evaluated at those samples
    """
    assert len(samples) == len(probs)
    assert len(samples) > 100, 'WARNING imprecision; use more samples'
    pairs = zip(samples, probs)
    pairs.sort()
    samples = numpy.array([x for x, p in pairs])
    probs = numpy.array([p for x, p in pairs])
    density = len(samples) * numpy.sqrt(probs[1:] * probs[:-1])
    gaps = samples[1:] - samples[:-1]
    exp_samples = density * gaps
    return exp_goodness_of_fit(exp_samples, plot, normalized, return_dict)

def volume_of_sphere(dim, radius):
    assert isinstance(dim, (int, long))
    return radius ** dim * pi ** (0.5 * dim) / gamma(0.5 * dim + 1)

def vector_density_goodness_of_fit(
        samples,
        probs,
        plot=False,
        normalized=True,
        return_dict=False):
    """
    Transform arbitrary multivariate continuous samples
    to unif01 distribution via nearest neighbor distribution [1,2,3]
    and assess goodness of fit via binned Pearson's chi^2 test.

    [1] http://projecteuclid.org/download/pdf_1/euclid.aop/1176993668
    [2] http://arxiv.org/pdf/1006.3019v2.pdf
    [3] http://en.wikipedia.org/wiki/Nearest_neighbour_distribution

    Inputs:
        samples - a list of real-vector-valued samples from a distribution
        probs - a list of probability densities evaluated at those samples
    """
    from sklearn.neighbors import NearestNeighbors
    assert samples
    assert len(samples) == len(probs)
    dim = len(samples[0])
    assert dim
    assert len(samples) > 1000 * dim, 'WARNING imprecision; use more samples'
    if not hasattr(samples[0], '__iter__'):
        samples = numpy.array([samples]).T
    neighbors = NearestNeighbors(n_neighbors=2).fit(samples)
    distances, indices = neighbors.kneighbors(samples)
    radii = distances[:, 1]
    density = len(samples) * numpy.array(probs)
    volume = volume_of_sphere(dim, radii)
    exp_samples = density * volume
    return exp_goodness_of_fit(exp_samples, plot, normalized, return_dict)

def auto_density_goodness_of_fit(
        samples,
        probs,
        plot=False,
        normalized=True,
        return_dict=False):
    assert samples
    if len(samples[0]) == 1:
        fun = density_goodness_of_fit
    else:
        fun = vector_density_goodness_of_fit
    return fun(samples, probs, plot, normalized, return_dict)

def discrete_goodness_of_fit(
        samples,
        probs_dict,
        truncate_beyond=8,
        plot=False,
        normalized=True):
    """
    Transform arbitrary discrete data to multinomial
    and assess goodness of fit via Pearson's chi^2 test.
    """
    if not normalized:
        norm = sum(probs_dict.itervalues())
        probs_dict = {i: p / norm for i, p in probs_dict.iteritems()}
    counts = defaultdict(lambda: 0)
    for sample in samples:
        assert sample in probs_dict
        counts[sample] += 1
    items = [(prob, counts.get(i, 0)) for i, prob in probs_dict.iteritems()]
    items.sort(reverse=True)
    truncated = (truncate_beyond and truncate_beyond < len(items))
    if truncated:
        items = items[:truncate_beyond]
    probs = [prob for prob, count in items]
    counts = [count for prob, count in items]
    assert sum(counts) > 100, 'WARNING imprecision; use more samples'
    return multinomial_goodness_of_fit(
        probs,
        counts,
        len(samples),
        truncated=truncated,
        plot=plot)

NoneType = type(None)

def split_discrete_continuous(data):
    """
    Convert arbitrary data to a pair `(discrete, continuous)`
    where `discrete` is hashable and `continuous` is a list of floats.
    """
    if isinstance(data, (NoneType, bool, int, long, basestring)):
        return data, []
    elif isinstance(data, (float, numpy.float32, numpy.float64)):
        return None, [data]
    elif isinstance(data, (tuple, list)):
        discrete = []
        continuous = []
        for part in data:
            d, c = split_discrete_continuous(part)
            discrete.append(d)
            continuous += c
        return tuple(discrete), continuous
    elif isinstance(data, numpy.ndarray):
        assert data.dtype in [numpy.float64, numpy.float32]
        return (None,) * len(data), map(float, data)
    else:
        raise TypeError(
            'split_discrete_continuous does not accept {} of type {}'.format(
                repr(data), str(type(data))))

def mixed_density_goodness_of_fit(
        samples,
        scores,
        plot=False,
        normalized=True):
    """
    Test general mixed discrete+continuous datatypes by
    (1) testing the continuous part conditioned on each discrete value
    (2) testing the discrete part marginalizing over the continuous part
    (3) testing the estimated total probability (if normalized = True)

    Inputs:
        samples - a list of real-vector-valued samples from a distribution
        probs - a list of probability densities evaluated at those samples
    """
    assert samples
    discrete_samples = []
    strata = defaultdict(lambda: ([], []))
    for sample, score in izip(samples, scores):
        d, c = split_discrete_continuous(sample)
        discrete_samples.append(d)
        samples, scores = strata[d]
        samples.append(c)
        scores.append(score)

    # Continuous part
    gofs = []
    discrete_probs = {}
    for key, (samples, scores) in strata.iteritems():
        if len(samples[0]) == 1:
            discrete_probs[key] = numpy.exp(scores[0])
        else:
            result = auto_density_goodness_of_fit(
                samples,
                scores,
                plot=plot,
                normalized=False,
                return_dict=True)
            gofs.append(result['gof'])
            discrete_probs[key] = result['norm']

    # Discrete part
    if len(strata) > 1:
        gofs.append(discrete_goodness_of_fit(
            discrete_samples,
            discrete_probs,
            plot=plot,
            normalized=False))

    # Normalization
    if normalized:
        norm = sum(discrete_probs.itervalues())
        discrete_counts = [len(samples) for samples, _ in strata.itervalues()]
        norm_variance = sum(1.0 / count for count in discrete_counts)
        dof = len(discrete_counts)
        chi_squared = (1 - norm) ** 2 / norm_variance
        gofs.append(scipy.stats.chi2.sf(chi_squared, dof))

    return min(gofs)

def bin_samples(samples, k=10, support=[]):
    """
    Bins a collection of univariate samples into k bins of equal
    fill via the empirical cdf, to be used in goodness of fit testing.

    Returns
    counts : array k x 1
    bin_ranges : arrary k x 2

    each count is the number of samples in [bin_min, bin_max)
    except for the last bin which is [bin_min, bin_max]

    list partitioning algorithm adapted from Mark Dickinson:
    http://stackoverflow.com/questions/2659900
    """
    samples = sorted(samples)

    N = len(samples)
    q, r = divmod(N, k)
    # We need to distribute the remainder relatively evenly;
    # tests will be inaccurate if we have small bins at the end.
    indices = [i * q + min(r, i) for i in range(k + 1)]
    bins = [samples[indices[i]: indices[i + 1]] for i in range(k)]
    bin_ranges = []
    counts = []
    for i in range(k):
        bin_min = bins[i][0]
        try:
            bin_max = bins[i + 1][0]
        except IndexError:
            bin_max = bins[i][-1]
        bin_ranges.append([bin_min, bin_max])
        counts.append(len(bins[i]))
    if support:
        bin_ranges[0][0] = support[0]
        bin_ranges[-1][1] = support[1]
    return numpy.array(counts), numpy.array(bin_ranges)

def histogram(samples, bin_count=None):
    if bin_count is None:
        bin_count = numpy.max(samples) + 1
    v = numpy.zeros(bin_count, dtype=int)
    for sample in samples:
        v[sample] += 1
    return v
<|endoftext|>


<commit_before>def readchar(filename):
    for char in open(filename).read():
        yield char

def bdecode(filename):

    def get_val():
        i = reader.next()
        if i.isdigit():
            str_len = get_len(i)
            return get_str(str_len)
        if i == 'd':
            return get_dict()
        if i == 'l':
            return get_list()
        if i == 'i':
            return get_int()
        if i == 'e':
            return None

    def get_len(i=''):
        len_str = str(i)
        next_char = reader.next()
        if next_char == 'e':  # The line that collapses the dictionary
            return next_char
        while next_char is not ':':
            len_str += next_char
            next_char = reader.next()
        else:
            return int(len_str)

    def get_dict():
        this_dict = {}
        while 1:
            str_len = get_len()
            if str_len == 'e':  # This dict is done
                return this_dict
            key = get_str(str_len)
            val = get_val()
            this_dict[key] = val

    def get_int():
        int_str = ''
        i = reader.next()
        while i is not 'e':
            int_str += i
            i = reader.next()
        else:
            return int(int_str)

    def get_str(str_len):
        this_str = ''
        for i in range(str_len):
            this_str += reader.next()
        return this_str

    def get_list():
        this_list = []
        while 1:
            val = get_val()
            if not val:
                return this_list
            this_list.append(val)

    reader = readchar(filename)
    dict_repr = get_val()
    return dict_repr
<commit_msg>Got bencode working and passing tests<commit_after>def _readchar(filename):
    for char in open(filename).read():
        yield char

def bencode(in_dict):

    def encode_str(in_str):
        out_str = str(len(in_str)) + ':' + in_str
        return out_str

    def encode_int(in_int):
        out_str = str('i' + str(in_int) + 'e')
        return out_str

    def encode_list(in_list):
        out_str = 'l'
        for item in in_list:
            out_str += encode_item(item)
        else:
            out_str += 'e'
        return out_str

    def encode_dict(in_dict):
        out_str = 'd'
        while in_dict:
            item = in_dict.popitem()
            for i in item:
                out_str += encode_item(i)
        else:
            out_str += 'e'
        return out_str

    def encode_item(x):
        if isinstance(x, str):
            return encode_str(x)
        elif isinstance(x, int):
            return encode_int(x)
        elif isinstance(x, list):
            return encode_list(x)
        elif isinstance(x, dict):
            return encode_dict(x)

    return encode_item(in_dict)

def bdecode(filename):

    def get_val():
        i = reader.next()
        if i.isdigit():
            str_len = get_len(i)
            return get_str(str_len)
        if i == 'd':
            return get_dict()
        if i == 'l':
            return get_list()
        if i == 'i':
            return get_int()
        if i == 'e':
            return None

    def get_len(i=''):
        len_str = str(i)
        next_char = reader.next()
        if next_char == 'e':  # The line that collapses the dictionary
            return next_char
        while next_char is not ':':
            len_str += next_char
            next_char = reader.next()
        else:
            return int(len_str)

    def get_dict():
        this_dict = {}
        while 1:
            str_len = get_len()
            if str_len == 'e':  # This dict is done
                return this_dict
            key = get_str(str_len)
            val = get_val()
            this_dict[key] = val

    def get_int():
        int_str = ''
        i = reader.next()
        while i is not 'e':
            int_str += i
            i = reader.next()
        else:
            return int(int_str)

    def get_str(str_len):
        this_str = ''
        for i in range(str_len):
            this_str += reader.next()
        return this_str

    def get_list():
        this_list = []
        while 1:
            val = get_val()
            if not val:
                return this_list
            this_list.append(val)

    reader = _readchar(filename)
    dict_repr = get_val()
    return dict_repr
<|endoftext|>


<commit_before>import os
from django.conf import settings
from django.core import signals
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import curry

__all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError')

if not settings.DATABASE_ENGINE:
    settings.DATABASE_ENGINE = 'dummy'

try:
    # Most of the time, the database backend will be one of the official
    # backends that ships with Django, so look there first.
    _import_path = 'django.db.backends.'
    backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
except ImportError, e:
    # If the import failed, we might be looking for a database backend
    # distributed external to Django. So we'll try that next.
    try:
        _import_path = ''
        backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, [''])
    except ImportError, e_user:
        # The database backend wasn't found. Display a helpful error message
        # listing all possible (built-in) database backends.
        backend_dir = os.path.join(__path__[0], 'backends')
        available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
        available_backends.sort()
        if settings.DATABASE_ENGINE not in available_backends:
            raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s\nError was: %s" % \
                (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)), e_user)
        else:
            raise # If there's some other error, this must be an error in Django itself.

# Convenient aliases for backend bits.
connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS)
DatabaseError = backend.DatabaseError
IntegrityError = backend.IntegrityError

# Register an event that closes the database connection
# when a Django request is finished.
def close_connection(**kwargs):
    connection.close()
signals.request_finished.connect(close_connection)

# Register an event that resets connection.queries
# when a Django request is started.
def reset_queries(**kwargs):
    connection.queries = []
signals.request_started.connect(reset_queries)

# Register an event that rolls back the connection
# when a Django request has an exception.
def _rollback_on_exception(**kwargs):
    from django.db import transaction
    transaction.rollback_unless_managed()
signals.got_request_exception.connect(_rollback_on_exception)
<commit_msg>Fixed #8315 -- If an exception is raised whilst trying to rollback a transaction (after another exception in the code), make sure the original exception is reported, rather than the rollback-generated one. The latter is almost certainly a consequence of the former. Patch from Karen Tracey.<commit_after>import os
from django.conf import settings
from django.core import signals
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import curry

__all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError')

if not settings.DATABASE_ENGINE:
    settings.DATABASE_ENGINE = 'dummy'

try:
    # Most of the time, the database backend will be one of the official
    # backends that ships with Django, so look there first.
    _import_path = 'django.db.backends.'
    backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
except ImportError, e:
    # If the import failed, we might be looking for a database backend
    # distributed external to Django. So we'll try that next.
    try:
        _import_path = ''
        backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, [''])
    except ImportError, e_user:
        # The database backend wasn't found. Display a helpful error message
        # listing all possible (built-in) database backends.
        backend_dir = os.path.join(__path__[0], 'backends')
        available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
        available_backends.sort()
        if settings.DATABASE_ENGINE not in available_backends:
            raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s\nError was: %s" % \
                (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)), e_user)
        else:
            raise # If there's some other error, this must be an error in Django itself.

# Convenient aliases for backend bits.
connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS)
DatabaseError = backend.DatabaseError
IntegrityError = backend.IntegrityError

# Register an event that closes the database connection
# when a Django request is finished.
def close_connection(**kwargs):
    connection.close()
signals.request_finished.connect(close_connection)

# Register an event that resets connection.queries
# when a Django request is started.
def reset_queries(**kwargs):
    connection.queries = []
signals.request_started.connect(reset_queries)

# Register an event that rolls back the connection
# when a Django request has an exception.
def _rollback_on_exception(**kwargs):
    from django.db import transaction
    try:
        transaction.rollback_unless_managed()
    except DatabaseError:
        pass
signals.got_request_exception.connect(_rollback_on_exception)
<|endoftext|>


<commit_before>def _readchar(filename):
    for char in open(filename).read():
        yield char

def bencode(in_dict):

    def encode_str(in_str):
        out_str = str(len(in_str)) + ':' + in_str
        return out_str

    def encode_int(in_int):
        out_str = str('i' + str(in_int) + 'e')
        return out_str

    def encode_list(in_list):
        out_str = 'l'
        for item in in_list:
            out_str += encode_item(item)
        else:
            out_str += 'e'
        return out_str

    def encode_dict(in_dict):
        out_str = 'd'
        while in_dict:
            item = in_dict.popitem()
            for i in item:
                out_str += encode_item(i)
        else:
            out_str += 'e'
        return out_str

    def encode_item(x):
        if isinstance(x, str):
            return encode_str(x)
        elif isinstance(x, int):
            return encode_int(x)
        elif isinstance(x, list):
            return encode_list(x)
        elif isinstance(x, dict):
            return encode_dict(x)

    return encode_item(in_dict)

def bdecode(filename):

    def get_val():
        i = reader.next()
        if i.isdigit():
            str_len = get_len(i)
            return get_str(str_len)
        if i == 'd':
            return get_dict()
        if i == 'l':
            return get_list()
        if i == 'i':
            return get_int()
        if i == 'e':
            return None

    def get_len(i=''):
        len_str = str(i)
        next_char = reader.next()
        if next_char == 'e':  # The line that collapses the dictionary
            return next_char
        while next_char is not ':':
            len_str += next_char
            next_char = reader.next()
        else:
            return int(len_str)

    def get_dict():
        this_dict = {}
        while 1:
            str_len = get_len()
            if str_len == 'e':  # This dict is done
                return this_dict
            key = get_str(str_len)
            val = get_val()
            this_dict[key] = val

    def get_int():
        int_str = ''
        i = reader.next()
        while i is not 'e':
            int_str += i
            i = reader.next()
        else:
            return int(int_str)

    def get_str(str_len):
        this_str = ''
        for i in range(str_len):
            this_str += reader.next()
        return this_str

    def get_list():
        this_list = []
        while 1:
            val = get_val()
            if not val:
                return this_list
            this_list.append(val)

    reader = _readchar(filename)
    dict_repr = get_val()
    return dict_repr
<commit_msg>Added a second method to bdecode a string. Necessary for GET request.<commit_after>def _readchar(bstring):
    for char in bstring:
        yield char

def bencode(in_dict):
    '''
        Turns a dictionary into a bencoded str with alphabetized keys
        e.g., {'spam': 'eggs', 'cow': 'moo'} --> d3:cow3:moo4:spam4:eggse
    '''

    def encode_str(in_str):
        out_str = str(len(in_str)) + ':' + in_str
        return out_str

    def encode_int(in_int):
        out_str = str('i' + str(in_int) + 'e')
        return out_str

    def encode_list(in_list):
        out_str = 'l'
        for item in in_list:
            out_str += encode_item(item)
        else:
            out_str += 'e'
        return out_str

    def encode_dict(in_dict):
        out_str = 'd'
        keys = in_dict.keys().sorted()
        while in_dict:
            for key in keys:
                val = in_dict.pop(key)
                out_str = out_str + encode_item(key) + encode_item(val)
            else:
                out_str += 'e'
        return out_str

    def encode_item(x):
        if isinstance(x, str):
            return encode_str(x)
        elif isinstance(x, int):
            return encode_int(x)
        elif isinstance(x, list):
            return encode_list(x)
        elif isinstance(x, dict):
            return encode_dict(x)

    return encode_item(in_dict)

def bdecodes(bstring):
    '''
        Bdecodes a bencoded string
        e.g., d3:cow3:moo4:spam4:eggse -> {'cow': 'moo', 'spam': 'eggs'}
    '''

    def get_val():
        i = reader.next()
        if i.isdigit():
            str_len = get_len(i)
            return get_str(str_len)
        if i == 'd':
            return get_dict()
        if i == 'l':
            return get_list()
        if i == 'i':
            return get_int()
        if i == 'e':
            return None

    def get_len(i=''):
        len_str = str(i)
        next_char = reader.next()
        if next_char == 'e':  # The line that collapses the dictionary
            return next_char
        while next_char is not ':':
            len_str += next_char
            next_char = reader.next()
        else:
            return int(len_str)

    def get_dict():
        this_dict = {}
        while 1:
            str_len = get_len()
            if str_len == 'e':  # This dict is done
                return this_dict
            key = get_str(str_len)
            val = get_val()
            this_dict[key] = val

    def get_int():
        int_str = ''
        i = reader.next()
        while i is not 'e':
            int_str += i
            i = reader.next()
        else:
            return int(int_str)

    def get_str(str_len):
        this_str = ''
        for i in range(str_len):
            this_str += reader.next()
        return this_str

    def get_list():
        this_list = []
        while 1:
            val = get_val()
            if not val:
                return this_list
            this_list.append(val)

    reader = _readchar(bstring)
    dict_repr = get_val()
    return dict_repr

def bdecode(filename):
    '''
        Bdecodes a .torrent or other bencoded file
    '''
    with open(filename) as f:
        return bdecodes(f.read())
<|endoftext|>


<commit_before>import os
import base64
from search.models import SearchTerm
from pyment.settings import PRODUCTS_PER_ROW
from meadery.models import Product
from stats.models import ProductView

def tracking_id(request):
    try:
        return request.session['tracking_id']
    except KeyError:
        request.session['tracking_id'] = base64.b64encode(os.urandom(36))
        return request.session['tracking_id']

def recommended_from_search(request):
    # get the common words from the stored searches
    common_words = frequent_search_words(request)
    from search import search
    matching = []
    for word in common_words:
        results = search.products(word).get('products', [])
        for r in results:
            if len(matching) < PRODUCTS_PER_ROW and r not in matching:
                matching.append(r)
    return matching

def frequent_search_words(request):
    # get the ten most recent searches from the database.
    searches = SearchTerm.objects.filter(tracking_id=tracking_id(request)).values('q').order_by('-search_date')[0:10]
    # join all of the searches together into a single string.
    search_string = ' '.join([search['q'] for search in searches])
    # return the top three most common words in the searches
    return sort_words_by_frequency(search_string)[0:3]

def sort_words_by_frequency(some_string):
    # convert the string to a python list
    words = some_string.split()
    # assign a rank to each word based on frequency
    ranked_words = [[word, words.count(word)] for word in set(words)]
    # sort the words based on descending frequency
    sorted_words = sorted(ranked_words, key=lambda word: -word[1])
    # return the list of words, most frequent first
    return [p[0] for p in sorted_words]

def log_product_view(request, product):
    t_id = tracking_id(request)
    try:
        v = ProductView.objects.get(tracking_id=t_id, product=product)
        v.save()
    except ProductView.DoesNotExist:
        v = ProductView()
        v.product = product
        v.ip_address = request.META.get('REMOTE_ADDR')
        if not request.META.get('REMOTE_ADDR'):
            v.ip_address = '127.0.0.1'
        v.tracking_id = t_id
        v.user = None
        if request.user.is_authenticated:
            v.user = request.user
        v.save()

def recommended_from_views(request):
    # JMT: t_id wasn't used, figure out why
    # t_id = tracking_id(request)
    # get recently viewed products
    viewed = get_recently_viewed(request)
    # if there are previously viewed products, get other tracking ids that have
    # viewed those products also
    if viewed:
        productviews = ProductView.objects.filter(product__in=viewed).values('tracking_id')
        t_ids = [v['tracking_id'] for v in productviews]
        # if there are other tracking ids, get other products.
        if t_ids:
            all_viewed = Product.instock.filter(is_active=True).filter(productview__tracking_id__in=t_ids)
            # if there are other products, get them, excluding the
            # products that the customer has already viewed.
            if all_viewed:
                other_viewed = ProductView.objects.filter(product__in=all_viewed).exclude(product__in=viewed)
                if other_viewed:
                    return Product.instock.filter(is_active=True).filter(productview__in=other_viewed).distinct()

def get_recently_viewed(request):
    t_id = tracking_id(request)
    views = ProductView.objects.filter(tracking_id=t_id).values('product_id').order_by('-date')[0:PRODUCTS_PER_ROW]
    product_ids = [v['product_id'] for v in views]
    return Product.active.filter(id__in=product_ids)
<commit_msg>Remove out-of-stock items from recently-viewed item list. (#110)<commit_after>import os
import base64
from search.models import SearchTerm
from pyment.settings import PRODUCTS_PER_ROW
from meadery.models import Product
from stats.models import ProductView

def tracking_id(request):
    try:
        return request.session['tracking_id']
    except KeyError:
        request.session['tracking_id'] = base64.b64encode(os.urandom(36))
        return request.session['tracking_id']

def recommended_from_search(request):
    # get the common words from the stored searches
    common_words = frequent_search_words(request)
    from search import search
    matching = []
    for word in common_words:
        results = search.products(word).get('products', [])
        for r in results:
            if len(matching) < PRODUCTS_PER_ROW and r not in matching:
                matching.append(r)
    return matching

def frequent_search_words(request):
    # get the ten most recent searches from the database.
    searches = SearchTerm.objects.filter(tracking_id=tracking_id(request)).values('q').order_by('-search_date')[0:10]
    # join all of the searches together into a single string.
    search_string = ' '.join([search['q'] for search in searches])
    # return the top three most common words in the searches
    return sort_words_by_frequency(search_string)[0:3]

def sort_words_by_frequency(some_string):
    # convert the string to a python list
    words = some_string.split()
    # assign a rank to each word based on frequency
    ranked_words = [[word, words.count(word)] for word in set(words)]
    # sort the words based on descending frequency
    sorted_words = sorted(ranked_words, key=lambda word: -word[1])
    # return the list of words, most frequent first
    return [p[0] for p in sorted_words]

def log_product_view(request, product):
    t_id = tracking_id(request)
    try:
        v = ProductView.objects.get(tracking_id=t_id, product=product)
        v.save()
    except ProductView.DoesNotExist:
        v = ProductView()
        v.product = product
        v.ip_address = request.META.get('REMOTE_ADDR')
        if not request.META.get('REMOTE_ADDR'):
            v.ip_address = '127.0.0.1'
        v.tracking_id = t_id
        v.user = None
        if request.user.is_authenticated:
            v.user = request.user
        v.save()

def recommended_from_views(request):
    # JMT: t_id wasn't used, figure out why
    # t_id = tracking_id(request)
    # get recently viewed products
    viewed = get_recently_viewed(request)
    # if there are previously viewed products, get other tracking ids that have
    # viewed those products also
    if viewed:
        productviews = ProductView.objects.filter(product__in=viewed).values('tracking_id')
        t_ids = [v['tracking_id'] for v in productviews]
        # if there are other tracking ids, get other products.
        if t_ids:
            all_viewed = Product.instock.filter(is_active=True).filter(productview__tracking_id__in=t_ids)
            # if there are other products, get them, excluding the
            # products that the customer has already viewed.
            if all_viewed:
                other_viewed = ProductView.objects.filter(product__in=all_viewed).exclude(product__in=viewed)
                if other_viewed:
                    return Product.instock.filter(is_active=True).filter(productview__in=other_viewed).distinct()

def get_recently_viewed(request):
    t_id = tracking_id(request)
    views = ProductView.objects.filter(tracking_id=t_id).values('product_id').order_by('-date')[0:PRODUCTS_PER_ROW]
    product_ids = [v['product_id'] for v in views]
    return Product.instock.filter(id__in=product_ids)
<|endoftext|>


<commit_before>import sys
import signal
import unittest

from django.conf import settings
from django.db.models import get_app, get_apps
from django.test import _doctest as doctest
from django.test.utils import setup_test_environment, teardown_test_environment
from django.test.testcases import OutputChecker, DocTestRunner, TestCase

# The module name for tests outside models.py
TEST_MODULE = 'tests'

doctestOutputChecker = OutputChecker()

class DjangoTestRunner(unittest.TextTestRunner):

    def __init__(self, verbosity=0, failfast=False, **kwargs):
        super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
        self.failfast = failfast
        self._keyboard_interrupt_intercepted = False

    def run(self, *args, **kwargs):
        """
        Runs the test suite after registering a custom signal handler
        that triggers a graceful exit when Ctrl-C is pressed.
        """
        self._default_keyboard_interrupt_handler = signal.signal(signal.SIGINT,
            self._keyboard_interrupt_handler)
        result = super(DjangoTestRunner, self).run(*args, **kwargs)
        signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
        return result

    def _keyboard_interrupt_handler(self, signal_number, stack_frame):
        """
        Handles Ctrl-C by setting a flag that will stop the test run when
        the currently running test completes.
        """
        self._keyboard_interrupt_intercepted = True
        sys.stderr.write(" <Test run halted by Ctrl-C> ")
        # Set the interrupt handler back to the default handler, so that
        # another Ctrl-C press will trigger immediate exit.
        signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)

    def _makeResult(self):
        result = super(DjangoTestRunner, self)._makeResult()
        failfast = self.failfast

        def stoptest_override(func):
            def stoptest(test):
                # If we were set to failfast and the unit test failed,
                # or if the user has typed Ctrl-C, report and quit
                if (failfast and not result.wasSuccessful()) or \
                    self._keyboard_interrupt_intercepted:
                    result.stop()
                func(test)
            return stoptest

        setattr(result, 'stopTest', stoptest_override(result.stopTest))
        return result

def get_tests(app_module):
    try:
        app_path = app_module.__name__.split('.')[:-1]
        test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
    except ImportError, e:
        # Couldn't import tests.py. Was it due to a missing file, or
        # due to an import error in a tests.py that actually exists?
        import os.path
        from imp import find_module
        try:
            mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
        except ImportError:
            # 'tests' module doesn't exist. Move on.
            test_module = None
        else:
            # The module exists, so there must be an import error in the
            # test module itself. We don't need the module; so if the
            # module was a single file module (i.e., tests.py), close the file
            # handle returned by find_module. Otherwise, the test module
            # is a directory, and there is nothing to close.
            if mod[0]:
                mod[0].close()
            raise
    return test_module

def build_suite(app_module):
    "Create a complete Django test suite for the provided application module"
    suite = unittest.TestSuite()

    # Load unit and doctests in the models.py module. If module has
    # a suite() method, use it. Otherwise build the test suite ourselves.
    if hasattr(app_module, 'suite'):
        suite.addTest(app_module.suite())
    else:
        suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
        try:
            suite.addTest(doctest.DocTestSuite(app_module,
                                               checker=doctestOutputChecker,
                                               runner=DocTestRunner))
        except ValueError:
            # No doc tests in models.py
            pass

    # Check to see if a separate 'tests' module exists parallel to the
    # models module
    test_module = get_tests(app_module)
    if test_module:
        # Load unit and doctests in the tests.py module. If module has
        # a suite() method, use it. Otherwise build the test suite ourselves.
        if hasattr(test_module, 'suite'):
            suite.addTest(test_module.suite())
        else:
            suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
            try:
                suite.addTest(doctest.DocTestSuite(test_module,
                                                   checker=doctestOutputChecker,
                                                   runner=DocTestRunner))
            except ValueError:
                # No doc tests in tests.py
                pass
    return suite

def build_test(label):
    """Construct a test case a test with the specified label. Label should
    be of the form model.TestClass or model.TestClass.test_method. Returns
    an instantiated test or test suite corresponding to the label provided.

    """
    parts = label.split('.')
    if len(parts) < 2 or len(parts) > 3:
        raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label)

    app_module = get_app(parts[0])
    TestClass = getattr(app_module, parts[1], None)

    # Couldn't find the test class in models.py; look in tests.py
    if TestClass is None:
        test_module = get_tests(app_module)
        if test_module:
            TestClass = getattr(test_module, parts[1], None)

    if len(parts) == 2: # label is app.TestClass
        try:
            return unittest.TestLoader().loadTestsFromTestCase(TestClass)
        except TypeError:
            raise ValueError("Test label '%s' does not refer to a test class" % label)
    else: # label is app.TestClass.test_method
        if not TestClass:
            raise ValueError("Test label '%s' does not refer to a test class" % label)
        return TestClass(parts[2])

# Python 2.3 compatibility: TestSuites were made iterable in 2.4.
# We need to iterate over them, so we add the missing method when
# necessary.
try:
    getattr(unittest.TestSuite, '__iter__')
except AttributeError:
    setattr(unittest.TestSuite, '__iter__', lambda s: iter(s._tests))

def partition_suite(suite, classes, bins):
    """
    Partitions a test suite by test type.

    classes is a sequence of types
    bins is a sequence of TestSuites, one more than classes

    Tests of type classes[i] are added to bins[i],
    tests with no match found in classes are place in bins[-1]
    """
    for test in suite:
        if isinstance(test, unittest.TestSuite):
            partition_suite(test, classes, bins)
        else:
            for i in range(len(classes)):
                if isinstance(test, classes[i]):
                    bins[i].addTest(test)
                    break
            else:
                bins[-1].addTest(test)

def reorder_suite(suite, classes):
    """
    Reorders a test suite by test type.

    classes is a sequence of types

    All tests of type clases[0] are placed first, then tests of type classes[1], etc.
    Tests with no match in classes are placed last.
    """
    class_count = len(classes)
    bins = [unittest.TestSuite() for i in range(class_count+1)]
    partition_suite(suite, classes, bins)
    for i in range(class_count):
        bins[0].addTests(bins[i+1])
    return bins[0]

def run_tests(test_labels, verbosity=1, interactive=True, failfast=False, extra_tests=[]):
    """
    Run the unit tests for all the test labels in the provided list.
    Labels must be of the form:
     - app.TestClass.test_method
        Run a single specific test method
     - app.TestClass
        Run all the test methods in a given class
     - app
        Search for doctests and unittests in the named application.

    When looking for tests, the test runner will look in the models and
    tests modules for the application.

    A list of 'extra' tests may also be provided; these tests
    will be added to the test suite.

    Returns the number of tests that failed.
    """
    setup_test_environment()

    settings.DEBUG = False
    suite = unittest.TestSuite()

    if test_labels:
        for label in test_labels:
            if '.' in label:
                suite.addTest(build_test(label))
            else:
                app = get_app(label)
                suite.addTest(build_suite(app))
    else:
        for app in get_apps():
            suite.addTest(build_suite(app))

    for test in extra_tests:
        suite.addTest(test)

    suite = reorder_suite(suite, (TestCase,))

    from django.db import connections
    old_names = []
    for alias in connections:
        connection = connections[alias]
        old_names.append((connection, connection.settings_dict['NAME']))
        connection.creation.create_test_db(verbosity, autoclobber=not interactive)
    result = DjangoTestRunner(verbosity=verbosity, failfast=failfast).run(suite)
    for connection, old_name in old_names:
        connection.creation.destroy_test_db(old_name, verbosity)

    teardown_test_environment()

    return len(result.failures) + len(result.errors)
<commit_msg>Ensure the default keyboard interrupt handler is restored even if the test runner raises an exception.  Thanks Alex Gaynor.<commit_after>import sys
import signal
import unittest

from django.conf import settings
from django.db.models import get_app, get_apps
from django.test import _doctest as doctest
from django.test.utils import setup_test_environment, teardown_test_environment
from django.test.testcases import OutputChecker, DocTestRunner, TestCase

# The module name for tests outside models.py
TEST_MODULE = 'tests'

doctestOutputChecker = OutputChecker()

class DjangoTestRunner(unittest.TextTestRunner):

    def __init__(self, verbosity=0, failfast=False, **kwargs):
        super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
        self.failfast = failfast
        self._keyboard_interrupt_intercepted = False

    def run(self, *args, **kwargs):
        """
        Runs the test suite after registering a custom signal handler
        that triggers a graceful exit when Ctrl-C is pressed.
        """
        self._default_keyboard_interrupt_handler = signal.signal(signal.SIGINT,
            self._keyboard_interrupt_handler)
        try:
            result = super(DjangoTestRunner, self).run(*args, **kwargs)
        finally:
            signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
        return result

    def _keyboard_interrupt_handler(self, signal_number, stack_frame):
        """
        Handles Ctrl-C by setting a flag that will stop the test run when
        the currently running test completes.
        """
        self._keyboard_interrupt_intercepted = True
        sys.stderr.write(" <Test run halted by Ctrl-C> ")
        # Set the interrupt handler back to the default handler, so that
        # another Ctrl-C press will trigger immediate exit.
        signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)

    def _makeResult(self):
        result = super(DjangoTestRunner, self)._makeResult()
        failfast = self.failfast

        def stoptest_override(func):
            def stoptest(test):
                # If we were set to failfast and the unit test failed,
                # or if the user has typed Ctrl-C, report and quit
                if (failfast and not result.wasSuccessful()) or \
                    self._keyboard_interrupt_intercepted:
                    result.stop()
                func(test)
            return stoptest

        setattr(result, 'stopTest', stoptest_override(result.stopTest))
        return result

def get_tests(app_module):
    try:
        app_path = app_module.__name__.split('.')[:-1]
        test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
    except ImportError, e:
        # Couldn't import tests.py. Was it due to a missing file, or
        # due to an import error in a tests.py that actually exists?
        import os.path
        from imp import find_module
        try:
            mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
        except ImportError:
            # 'tests' module doesn't exist. Move on.
            test_module = None
        else:
            # The module exists, so there must be an import error in the
            # test module itself. We don't need the module; so if the
            # module was a single file module (i.e., tests.py), close the file
            # handle returned by find_module. Otherwise, the test module
            # is a directory, and there is nothing to close.
            if mod[0]:
                mod[0].close()
            raise
    return test_module

def build_suite(app_module):
    "Create a complete Django test suite for the provided application module"
    suite = unittest.TestSuite()

    # Load unit and doctests in the models.py module. If module has
    # a suite() method, use it. Otherwise build the test suite ourselves.
    if hasattr(app_module, 'suite'):
        suite.addTest(app_module.suite())
    else:
        suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
        try:
            suite.addTest(doctest.DocTestSuite(app_module,
                                               checker=doctestOutputChecker,
                                               runner=DocTestRunner))
        except ValueError:
            # No doc tests in models.py
            pass

    # Check to see if a separate 'tests' module exists parallel to the
    # models module
    test_module = get_tests(app_module)
    if test_module:
        # Load unit and doctests in the tests.py module. If module has
        # a suite() method, use it. Otherwise build the test suite ourselves.
        if hasattr(test_module, 'suite'):
            suite.addTest(test_module.suite())
        else:
            suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
            try:
                suite.addTest(doctest.DocTestSuite(test_module,
                                                   checker=doctestOutputChecker,
                                                   runner=DocTestRunner))
            except ValueError:
                # No doc tests in tests.py
                pass
    return suite

def build_test(label):
    """Construct a test case a test with the specified label. Label should
    be of the form model.TestClass or model.TestClass.test_method. Returns
    an instantiated test or test suite corresponding to the label provided.

    """
    parts = label.split('.')
    if len(parts) < 2 or len(parts) > 3:
        raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label)

    app_module = get_app(parts[0])
    TestClass = getattr(app_module, parts[1], None)

    # Couldn't find the test class in models.py; look in tests.py
    if TestClass is None:
        test_module = get_tests(app_module)
        if test_module:
            TestClass = getattr(test_module, parts[1], None)

    if len(parts) == 2: # label is app.TestClass
        try:
            return unittest.TestLoader().loadTestsFromTestCase(TestClass)
        except TypeError:
            raise ValueError("Test label '%s' does not refer to a test class" % label)
    else: # label is app.TestClass.test_method
        if not TestClass:
            raise ValueError("Test label '%s' does not refer to a test class" % label)
        return TestClass(parts[2])

# Python 2.3 compatibility: TestSuites were made iterable in 2.4.
# We need to iterate over them, so we add the missing method when
# necessary.
try:
    getattr(unittest.TestSuite, '__iter__')
except AttributeError:
    setattr(unittest.TestSuite, '__iter__', lambda s: iter(s._tests))

def partition_suite(suite, classes, bins):
    """
    Partitions a test suite by test type.

    classes is a sequence of types
    bins is a sequence of TestSuites, one more than classes

    Tests of type classes[i] are added to bins[i],
    tests with no match found in classes are place in bins[-1]
    """
    for test in suite:
        if isinstance(test, unittest.TestSuite):
            partition_suite(test, classes, bins)
        else:
            for i in range(len(classes)):
                if isinstance(test, classes[i]):
                    bins[i].addTest(test)
                    break
            else:
                bins[-1].addTest(test)

def reorder_suite(suite, classes):
    """
    Reorders a test suite by test type.

    classes is a sequence of types

    All tests of type clases[0] are placed first, then tests of type classes[1], etc.
    Tests with no match in classes are placed last.
    """
    class_count = len(classes)
    bins = [unittest.TestSuite() for i in range(class_count+1)]
    partition_suite(suite, classes, bins)
    for i in range(class_count):
        bins[0].addTests(bins[i+1])
    return bins[0]

def run_tests(test_labels, verbosity=1, interactive=True, failfast=False, extra_tests=[]):
    """
    Run the unit tests for all the test labels in the provided list.
    Labels must be of the form:
     - app.TestClass.test_method
        Run a single specific test method
     - app.TestClass
        Run all the test methods in a given class
     - app
        Search for doctests and unittests in the named application.

    When looking for tests, the test runner will look in the models and
    tests modules for the application.

    A list of 'extra' tests may also be provided; these tests
    will be added to the test suite.

    Returns the number of tests that failed.
    """
    setup_test_environment()

    settings.DEBUG = False
    suite = unittest.TestSuite()

    if test_labels:
        for label in test_labels:
            if '.' in label:
                suite.addTest(build_test(label))
            else:
                app = get_app(label)
                suite.addTest(build_suite(app))
    else:
        for app in get_apps():
            suite.addTest(build_suite(app))

    for test in extra_tests:
        suite.addTest(test)

    suite = reorder_suite(suite, (TestCase,))

    from django.db import connections
    old_names = []
    for alias in connections:
        connection = connections[alias]
        old_names.append((connection, connection.settings_dict['NAME']))
        connection.creation.create_test_db(verbosity, autoclobber=not interactive)
    result = DjangoTestRunner(verbosity=verbosity, failfast=failfast).run(suite)
    for connection, old_name in old_names:
        connection.creation.destroy_test_db(old_name, verbosity)

    teardown_test_environment()

    return len(result.failures) + len(result.errors)
<|endoftext|>