<commit_before>"""
Functions for explaining classifiers that use Image data.
"""
import copy

import numpy as np
import sklearn
import sklearn.preprocessing
from sklearn.utils import check_random_state

from . import lime_base
from .wrappers.scikit_image import SegmentationAlgorithm

class ImageExplanation(object):
    def __init__(self, image, segments):
        """Init function.

        Args:
            image: 3d numpy array
            segments: 2d numpy array, with the output from skimage.segmentation
        """
        self.image = image
        self.segments = segments
        self.intercept = {}
        self.local_exp = {}

    def get_image_and_mask(self, label, positive_only=True, hide_rest=False,
                           num_features=5, min_weight=0.):
        """Init function.

        Args:
            label: label to explain
            positive_only: if True, only take superpixels that contribute to
                the prediction of the label. Otherwise, use the top
                num_features superpixels, which can be positive or negative
                towards the label
            hide_rest: if True, make the non-explanation part of the return
                image gray
            num_features: number of superpixels to include in explanation
            min_weight: TODO

        Returns:
            (image, mask), where image is a 3d numpy array and mask is a 2d
            numpy array that can be used with
            skimage.segmentation.mark_boundaries
        """
        if label not in self.local_exp:
            raise KeyError('Label not in explanation')
        segments = self.segments
        image = self.image
        exp = self.local_exp[label]
        mask = np.zeros(segments.shape, segments.dtype)
        if hide_rest:
            temp = np.zeros(self.image.shape)
        else:
            temp = self.image.copy()
        if positive_only:
            fs = [x[0] for x in exp
                  if x[1] > 0 and x[1] > min_weight][:num_features]
            for f in fs:
                temp[segments == f] = image[segments == f].copy()
                mask[segments == f] = 1
            return temp, mask
        else:
            for f, w in exp[:num_features]:
                if np.abs(w) < min_weight:
                    continue
                c = 0 if w < 0 else 1
                mask[segments == f] = 1 if w < 0 else 2
                temp[segments == f] = image[segments == f].copy()
                temp[segments == f, c] = np.max(image)
                for cp in [0, 1, 2]:
                    if c == cp:
                        continue
                    # temp[segments == f, cp] *= 0.5
            return temp, mask

class LimeImageExplainer(object):
    """Explains predictions on Image (i.e. matrix) data.
    For numerical features, perturb them by sampling from a Normal(0,1) and
    doing the inverse operation of mean-centering and scaling, according to the
    means and stds in the training data. For categorical features, perturb by
    sampling according to the training distribution, and making a binary
    feature that is 1 when the value is the same as the instance being
    explained."""

    def __init__(self, kernel_width=.25, verbose=False,
                 feature_selection='auto', random_state=None):
        """Init function.

        Args:
            kernel_width: kernel width for the exponential kernel.
            If None, defaults to sqrt(number of columns) * 0.75
            verbose: if true, print local prediction values from linear model
            feature_selection: feature selection method. can be
                'forward_selection', 'lasso_path', 'none' or 'auto'.
                See function 'explain_instance_with_data' in lime_base.py for
                details on what each of the options does.
            random_state: an integer or numpy.RandomState that will be used to
                generate random numbers. If None, the random state will be
                initialized using the internal numpy seed.
        """
        kernel_width = float(kernel_width)

        def kernel(d):
            return np.sqrt(np.exp(-(d ** 2) / kernel_width ** 2))

        self.random_state = check_random_state(random_state)
        self.feature_selection = feature_selection
        self.base = lime_base.LimeBase(kernel, verbose, random_state=self.random_state)

    def explain_instance(self, image, classifier_fn, labels=(1,),
                         hide_color=None,
                         top_labels=5, num_features=100000, num_samples=1000,
                         batch_size=10,
                         segmentation_fn=None,
                         distance_metric='cosine',
                         model_regressor=None,
                         random_seed=None):
        """Generates explanations for a prediction.

        First, we generate neighborhood data by randomly perturbing features
        from the instance (see __data_inverse). We then learn locally weighted
        linear models on this neighborhood data to explain each of the classes
        in an interpretable way (see lime_base.py).

        Args:
            image: TODO
            classifier_fn: classifier prediction probability function, which
                takes a numpy array and outputs prediction probabilities.  For
                ScikitClassifiers , this is classifier.predict_proba.
            labels: iterable with labels to be explained.
            hide_color: TODO
            top_labels: if not None, ignore labels and produce explanations for
                the K labels with highest prediction probabilities, where K is
                this parameter.
            num_features: maximum number of features present in explanation
            num_samples: size of the neighborhood to learn the linear model
            batch_size: TODO
            distance_metric: the distance metric to use for weights.
            model_regressor: sklearn regressor to use in explanation. Defaults
            to Ridge regression in LimeBase. Must have model_regressor.coef_
            and 'sample_weight' as a parameter to model_regressor.fit()
            segmentation_fn: SegmentationAlgorithm, wrapped skimage
            segmentation function
            random_seed: integer used as random seed for the segmentation
                algorithm. If None, a random integer, between 0 and 1000,
                will be generated using the internal random number generator.

        Returns:
            An Explanation object (see explanation.py) with the corresponding
            explanations.
        """
        if random_seed is None:
            random_seed = self.random_state.randint(0, high=1000)

        if segmentation_fn is None:
            segmentation_fn = SegmentationAlgorithm('quickshift', kernel_size=4,
                                                    max_dist=200, ratio=0.2,
                                                    random_seed=random_seed)
        try:
            segments = segmentation_fn(image)
        except ValueError as e:
            raise e

        fudged_image = image.copy()
        if hide_color is None:
            for x in np.unique(segments):
                fudged_image[segments == x] = (
                    np.mean(image[segments == x][:, 0]),
                    np.mean(image[segments == x][:, 1]),
                    np.mean(image[segments == x][:, 2]))
        else:
            fudged_image[:] = hide_color

        top = labels

        data, labels = self.data_labels(image, fudged_image, segments,
                                        classifier_fn, num_samples,
                                        batch_size=batch_size)

        distances = sklearn.metrics.pairwise_distances(
            data,
            data[0].reshape(1, -1),
            metric=distance_metric
        ).ravel()

        ret_exp = ImageExplanation(image, segments)
        if top_labels:
            top = np.argsort(labels[0])[-top_labels:]
            ret_exp.top_labels = list(top)
            ret_exp.top_labels.reverse()
        for label in top:
            (ret_exp.intercept[label],
             ret_exp.local_exp[label],
             ret_exp.score) = self.base.explain_instance_with_data(
                data, labels, distances, label, num_features,
                model_regressor=model_regressor,
                feature_selection=self.feature_selection)
        return ret_exp

    def data_labels(self,
                    image,
                    fudged_image,
                    segments,
                    classifier_fn,
                    num_samples,
                    batch_size=10):
        """Generates images and predictions in the neighborhood of this image.

        Args:
            image: 3d numpy array, the image
            fudged_image: 3d numpy array, image to replace original image when
                superpixel is turned off
            segments: segmentation of the image
            classifier_fn: function that takes a list of images and returns a
                matrix of prediction probabilities
            num_samples: size of the neighborhood to learn the linear model
            batch_size: classifier_fn will be called on batches of this size.

        Returns:
            A tuple (data, labels), where:
                data: dense num_samples * num_superpixels
                labels: prediction probabilities matrix
        """
        n_features = np.unique(segments).shape[0]
        data = self.random_state.randint(0, 2, num_samples * n_features)\
            .reshape((num_samples, n_features))
        labels = []
        data[0, :] = 1
        imgs = []
        for row in data:
            temp = copy.deepcopy(image)
            zeros = np.where(row == 0)[0]
            mask = np.zeros(segments.shape).astype(bool)
            for z in zeros:
                mask[segments == z] = True
            temp[mask] = fudged_image[mask]
            imgs.append(temp)
            if len(imgs) == batch_size:
                preds = classifier_fn(np.array(imgs))
                labels.extend(preds)
                imgs = []
        if len(imgs) > 0:
            preds = classifier_fn(np.array(imgs))
            labels.extend(preds)
        return data, np.array(labels)
<commit_msg>Allowing for black & white images.<commit_after>"""
Functions for explaining classifiers that use Image data.
"""
import copy

import numpy as np
import sklearn
import sklearn.preprocessing
from sklearn.utils import check_random_state
from skimage.color import gray2rgb

from . import lime_base
from .wrappers.scikit_image import SegmentationAlgorithm

class ImageExplanation(object):
    def __init__(self, image, segments):
        """Init function.

        Args:
            image: 3d numpy array
            segments: 2d numpy array, with the output from skimage.segmentation
        """
        self.image = image
        self.segments = segments
        self.intercept = {}
        self.local_exp = {}

    def get_image_and_mask(self, label, positive_only=True, hide_rest=False,
                           num_features=5, min_weight=0.):
        """Init function.

        Args:
            label: label to explain
            positive_only: if True, only take superpixels that contribute to
                the prediction of the label. Otherwise, use the top
                num_features superpixels, which can be positive or negative
                towards the label
            hide_rest: if True, make the non-explanation part of the return
                image gray
            num_features: number of superpixels to include in explanation
            min_weight: TODO

        Returns:
            (image, mask), where image is a 3d numpy array and mask is a 2d
            numpy array that can be used with
            skimage.segmentation.mark_boundaries
        """
        if label not in self.local_exp:
            raise KeyError('Label not in explanation')
        segments = self.segments
        image = self.image
        exp = self.local_exp[label]
        mask = np.zeros(segments.shape, segments.dtype)
        if hide_rest:
            temp = np.zeros(self.image.shape)
        else:
            temp = self.image.copy()
        if positive_only:
            fs = [x[0] for x in exp
                  if x[1] > 0 and x[1] > min_weight][:num_features]
            for f in fs:
                temp[segments == f] = image[segments == f].copy()
                mask[segments == f] = 1
            return temp, mask
        else:
            for f, w in exp[:num_features]:
                if np.abs(w) < min_weight:
                    continue
                c = 0 if w < 0 else 1
                mask[segments == f] = 1 if w < 0 else 2
                temp[segments == f] = image[segments == f].copy()
                temp[segments == f, c] = np.max(image)
                for cp in [0, 1, 2]:
                    if c == cp:
                        continue
                    # temp[segments == f, cp] *= 0.5
            return temp, mask

class LimeImageExplainer(object):
    """Explains predictions on Image (i.e. matrix) data.
    For numerical features, perturb them by sampling from a Normal(0,1) and
    doing the inverse operation of mean-centering and scaling, according to the
    means and stds in the training data. For categorical features, perturb by
    sampling according to the training distribution, and making a binary
    feature that is 1 when the value is the same as the instance being
    explained."""

    def __init__(self, kernel_width=.25, verbose=False,
                 feature_selection='auto', random_state=None):
        """Init function.

        Args:
            kernel_width: kernel width for the exponential kernel.
            If None, defaults to sqrt(number of columns) * 0.75
            verbose: if true, print local prediction values from linear model
            feature_selection: feature selection method. can be
                'forward_selection', 'lasso_path', 'none' or 'auto'.
                See function 'explain_instance_with_data' in lime_base.py for
                details on what each of the options does.
            random_state: an integer or numpy.RandomState that will be used to
                generate random numbers. If None, the random state will be
                initialized using the internal numpy seed.
        """
        kernel_width = float(kernel_width)

        def kernel(d):
            return np.sqrt(np.exp(-(d ** 2) / kernel_width ** 2))

        self.random_state = check_random_state(random_state)
        self.feature_selection = feature_selection
        self.base = lime_base.LimeBase(kernel, verbose, random_state=self.random_state)

    def explain_instance(self, image, classifier_fn, labels=(1,),
                         hide_color=None,
                         top_labels=5, num_features=100000, num_samples=1000,
                         batch_size=10,
                         segmentation_fn=None,
                         distance_metric='cosine',
                         model_regressor=None,
                         random_seed=None):
        """Generates explanations for a prediction.

        First, we generate neighborhood data by randomly perturbing features
        from the instance (see __data_inverse). We then learn locally weighted
        linear models on this neighborhood data to explain each of the classes
        in an interpretable way (see lime_base.py).

        Args:
            image: 3 dimension RGB image. If this is only two dimensional,
                we will assume it's a grayscale image and call gray2rgb.
            classifier_fn: classifier prediction probability function, which
                takes a numpy array and outputs prediction probabilities.  For
                ScikitClassifiers , this is classifier.predict_proba.
            labels: iterable with labels to be explained.
            hide_color: TODO
            top_labels: if not None, ignore labels and produce explanations for
                the K labels with highest prediction probabilities, where K is
                this parameter.
            num_features: maximum number of features present in explanation
            num_samples: size of the neighborhood to learn the linear model
            batch_size: TODO
            distance_metric: the distance metric to use for weights.
            model_regressor: sklearn regressor to use in explanation. Defaults
            to Ridge regression in LimeBase. Must have model_regressor.coef_
            and 'sample_weight' as a parameter to model_regressor.fit()
            segmentation_fn: SegmentationAlgorithm, wrapped skimage
            segmentation function
            random_seed: integer used as random seed for the segmentation
                algorithm. If None, a random integer, between 0 and 1000,
                will be generated using the internal random number generator.

        Returns:
            An Explanation object (see explanation.py) with the corresponding
            explanations.
        """
        if len(image.shape) == 2:
            image = gray2rgb(image)
        if random_seed is None:
            random_seed = self.random_state.randint(0, high=1000)

        if segmentation_fn is None:
            segmentation_fn = SegmentationAlgorithm('quickshift', kernel_size=4,
                                                    max_dist=200, ratio=0.2,
                                                    random_seed=random_seed)
        try:
            segments = segmentation_fn(image)
        except ValueError as e:
            raise e

        fudged_image = image.copy()
        if hide_color is None:
            for x in np.unique(segments):
                fudged_image[segments == x] = (
                    np.mean(image[segments == x][:, 0]),
                    np.mean(image[segments == x][:, 1]),
                    np.mean(image[segments == x][:, 2]))
        else:
            fudged_image[:] = hide_color

        top = labels

        data, labels = self.data_labels(image, fudged_image, segments,
                                        classifier_fn, num_samples,
                                        batch_size=batch_size)

        distances = sklearn.metrics.pairwise_distances(
            data,
            data[0].reshape(1, -1),
            metric=distance_metric
        ).ravel()

        ret_exp = ImageExplanation(image, segments)
        if top_labels:
            top = np.argsort(labels[0])[-top_labels:]
            ret_exp.top_labels = list(top)
            ret_exp.top_labels.reverse()
        for label in top:
            (ret_exp.intercept[label],
             ret_exp.local_exp[label],
             ret_exp.score) = self.base.explain_instance_with_data(
                data, labels, distances, label, num_features,
                model_regressor=model_regressor,
                feature_selection=self.feature_selection)
        return ret_exp

    def data_labels(self,
                    image,
                    fudged_image,
                    segments,
                    classifier_fn,
                    num_samples,
                    batch_size=10):
        """Generates images and predictions in the neighborhood of this image.

        Args:
            image: 3d numpy array, the image
            fudged_image: 3d numpy array, image to replace original image when
                superpixel is turned off
            segments: segmentation of the image
            classifier_fn: function that takes a list of images and returns a
                matrix of prediction probabilities
            num_samples: size of the neighborhood to learn the linear model
            batch_size: classifier_fn will be called on batches of this size.

        Returns:
            A tuple (data, labels), where:
                data: dense num_samples * num_superpixels
                labels: prediction probabilities matrix
        """
        n_features = np.unique(segments).shape[0]
        data = self.random_state.randint(0, 2, num_samples * n_features)\
            .reshape((num_samples, n_features))
        labels = []
        data[0, :] = 1
        imgs = []
        for row in data:
            temp = copy.deepcopy(image)
            zeros = np.where(row == 0)[0]
            mask = np.zeros(segments.shape).astype(bool)
            for z in zeros:
                mask[segments == z] = True
            temp[mask] = fudged_image[mask]
            imgs.append(temp)
            if len(imgs) == batch_size:
                preds = classifier_fn(np.array(imgs))
                labels.extend(preds)
                imgs = []
        if len(imgs) > 0:
            preds = classifier_fn(np.array(imgs))
            labels.extend(preds)
        return data, np.array(labels)
<|endoftext|>


<commit_before>from django.conf import settings
from django.contrib import admin

from django import forms
from django.db import models

try:
    from funfactory.urlresolvers import reverse
except ImportError, e:
    from django.core.urlresolvers import reverse

from .models import (Badge, Award, Progress, DeferredAward)

UPLOADS_URL = getattr(settings, 'BADGER_UPLOADS_URL',
    '%suploads/' % getattr(settings, 'MEDIA_URL', '/media/'))

def show_unicode(obj):
    return unicode(obj)
show_unicode.short_description = "Display"

def show_image(obj):
    img_url = "%s%s" % (UPLOADS_URL, obj.image)
    return ('' %
        (img_url, img_url))

show_image.allow_tags = True
show_image.short_description = "Image"

def build_related_link(self, model_name, name_single, name_plural, qs):
    link = '%s?%s' % (
        reverse('admin:badger_%s_changelist' % model_name, args=[]),
        'badge__exact=%s' % (self.id)
    )
    new_link = '%s?%s' % (
        reverse('admin:badger_%s_add' % model_name, args=[]),
        'badge=%s' % (self.id)
    )
    count = qs.count()
    what = (count == 1) and name_single or name_plural
    return ('%s %s (new)' %
            (link, count, what, new_link))

def related_deferredawards_link(self):
    return build_related_link(self, 'deferredaward', 'deferred', 'deferred',
                              self.deferredaward_set)

related_deferredawards_link.allow_tags = True
related_deferredawards_link.short_description = "Deferred Awards"

def related_awards_link(self):
    return build_related_link(self, 'award', 'award', 'awards',
                              self.award_set)

related_awards_link.allow_tags = True
related_awards_link.short_description = "Awards"

class BadgeAdmin(admin.ModelAdmin):
    list_display = ("id", "title", show_image, "slug", "unique", "creator",
                    related_awards_link, related_deferredawards_link, "created",)
    list_display_links = ('id', 'title',)
    search_fields = ("title", "slug", "image", "description",)
    filter_horizontal = ('prerequisites', )
    prepopulated_fields = {"slug": ("title",)}
    formfield_overrides = {
        models.ManyToManyField: {
            "widget": forms.widgets.SelectMultiple(attrs={"size": 25})
        }
    }

def badge_link(self):
    url = reverse('admin:badger_badge_change', args=[self.badge.id])
    return '%s' % (url, self.badge)

badge_link.allow_tags = True
badge_link.short_description = 'Badge'

class AwardAdmin(admin.ModelAdmin):
    list_display = (show_unicode, badge_link, show_image, 'user', 'creator',
                    'created', )
    fields = ('badge', 'user', 'creator', )
    search_fields = ("badge__title", "badge__slug", "badge__description",)

class ProgressAdmin(admin.ModelAdmin):
    pass

def claim_code_link(self):
    return '%s' % (self.get_claim_url(), self.claim_code)

claim_code_link.allow_tags = True
claim_code_link.short_description = "Claim Code"

class DeferredAwardAdmin(admin.ModelAdmin):
    list_display = ('id', claim_code_link, 'claim_group', badge_link, 'email',
                    'reusable', 'creator', 'created', 'modified',)
    list_display_links = ('id',)
    list_filter = ('reusable', )
    fields = ('badge', 'claim_group', 'claim_code', 'email', 'reusable',
              'description',)
    readonly_fields = ('created', 'modified')
    search_fields = ("badge__title", "badge__slug", "badge__description",)

for x in ((Badge, BadgeAdmin),
          (Award, AwardAdmin),
          (Progress, ProgressAdmin),
          (DeferredAward, DeferredAwardAdmin),):
    admin.site.register(*x)
<commit_msg>Add claim_code to Award admin views<commit_after>from django.conf import settings
from django.contrib import admin

from django import forms
from django.db import models

try:
    from funfactory.urlresolvers import reverse
except ImportError, e:
    from django.core.urlresolvers import reverse

from .models import (Badge, Award, Progress, DeferredAward)

UPLOADS_URL = getattr(settings, 'BADGER_UPLOADS_URL',
    '%suploads/' % getattr(settings, 'MEDIA_URL', '/media/'))

def show_unicode(obj):
    return unicode(obj)
show_unicode.short_description = "Display"

def show_image(obj):
    img_url = "%s%s" % (UPLOADS_URL, obj.image)
    return ('' %
        (img_url, img_url))

show_image.allow_tags = True
show_image.short_description = "Image"

def build_related_link(self, model_name, name_single, name_plural, qs):
    link = '%s?%s' % (
        reverse('admin:badger_%s_changelist' % model_name, args=[]),
        'badge__exact=%s' % (self.id)
    )
    new_link = '%s?%s' % (
        reverse('admin:badger_%s_add' % model_name, args=[]),
        'badge=%s' % (self.id)
    )
    count = qs.count()
    what = (count == 1) and name_single or name_plural
    return ('%s %s (new)' %
            (link, count, what, new_link))

def related_deferredawards_link(self):
    return build_related_link(self, 'deferredaward', 'deferred', 'deferred',
                              self.deferredaward_set)

related_deferredawards_link.allow_tags = True
related_deferredawards_link.short_description = "Deferred Awards"

def related_awards_link(self):
    return build_related_link(self, 'award', 'award', 'awards',
                              self.award_set)

related_awards_link.allow_tags = True
related_awards_link.short_description = "Awards"

class BadgeAdmin(admin.ModelAdmin):
    list_display = ("id", "title", show_image, "slug", "unique", "creator",
                    related_awards_link, related_deferredawards_link, "created",)
    list_display_links = ('id', 'title',)
    search_fields = ("title", "slug", "image", "description",)
    filter_horizontal = ('prerequisites', )
    prepopulated_fields = {"slug": ("title",)}
    formfield_overrides = {
        models.ManyToManyField: {
            "widget": forms.widgets.SelectMultiple(attrs={"size": 25})
        }
    }

def badge_link(self):
    url = reverse('admin:badger_badge_change', args=[self.badge.id])
    return '%s' % (url, self.badge)

badge_link.allow_tags = True
badge_link.short_description = 'Badge'

class AwardAdmin(admin.ModelAdmin):
    list_display = (show_unicode, badge_link, show_image, 'claim_code', 'user',
                    'creator', 'created', )
    fields = ('badge', 'claim_code', 'user', 'creator', )
    search_fields = ("badge__title", "badge__slug", "badge__description",)

class ProgressAdmin(admin.ModelAdmin):
    pass

def claim_code_link(self):
    return '%s' % (self.get_claim_url(), self.claim_code)

claim_code_link.allow_tags = True
claim_code_link.short_description = "Claim Code"

class DeferredAwardAdmin(admin.ModelAdmin):
    list_display = ('id', claim_code_link, 'claim_group', badge_link, 'email',
                    'reusable', 'creator', 'created', 'modified',)
    list_display_links = ('id',)
    list_filter = ('reusable', )
    fields = ('badge', 'claim_group', 'claim_code', 'email', 'reusable',
              'description',)
    readonly_fields = ('created', 'modified')
    search_fields = ("badge__title", "badge__slug", "badge__description",)

for x in ((Badge, BadgeAdmin),
          (Award, AwardAdmin),
          (Progress, ProgressAdmin),
          (DeferredAward, DeferredAwardAdmin),):
    admin.site.register(*x)
<|endoftext|>


<commit_before>import unittest
from pokeher.wiring import BufferPokerBot
from pokeher.theaigame import TheAiGameParserDelegate, TheAiGameActionDelegate
from pokeher.brain import Brain
from pokeher.cards import Card, Hand
from pokeher.timer import Timer
import pokeher.constants as C

class BrainTestBot(BufferPokerBot, TheAiGameParserDelegate, TheAiGameActionDelegate):
    def add_brain(self):
        self.brain = Brain(self)

    def log(self, msg):
        pass

class BrainTest(unittest.TestCase):
    def setUp(self):
        self.fake_in = []
        self.fake_out = []
        self.fake_log = []
        self.data = MockData()
        self.data.to_call = 20
        self.data.pot = 140
        self.data.hand = Hand(Card(C.ACE, C.DIAMONDS), Card(C.ACE, C.HEARTS))
        self.data.table_cards = []
        self.data.me = 'bot_0'
        self.data.bets = {}

    def test_got_output(self):
        """Tests that the bot does something when it hits the turn marker"""
        self.fake_in = ['Settings your_bot bot_0',
                        'bot_0 hand [Ac,As]',
                        'Action bot_0 5000']
        bot = BrainTestBot(self.fake_in, self.fake_out, self.fake_log)
        bot.run()

        self.assertEqual(bot.brain.data.me, 'bot_0')
        self.assertTrue(bot.brain.data.hand)
        self.assertTrue(self.fake_out)

    def test_preflop_equity_loaded(self):
        """Tests that the preflop equity data loaded correctly"""
        bot = BrainTestBot(self.fake_in, self.fake_out, self.fake_log)
        self.assertTrue(bot.brain.preflop_equity)
        self.assertEqual(len(bot.brain.preflop_equity.keys()), 1326)

    def test_preflop_sanity(self):
        """Pull some stuff from the preflop equity and spot check it"""
        bot = BrainTestBot(self.fake_in, self.fake_out, self.fake_log)
        bad_hand = Hand(Card(2, C.CLUBS), Card(3, C.DIAMONDS))
        sample_key = repr(bad_hand)

        self.assertTrue(sample_key in bot.brain.preflop_equity.keys())
        bad_equity = bot.brain.preflop_equity[sample_key]
        self.assertTrue(bad_equity > 0.2)

        good_hand = Hand(Card(C.ACE, C.SPADES), Card(C.ACE, C.DIAMONDS))
        good_equity = bot.brain.preflop_equity[repr(good_hand)]
        self.assertTrue(good_equity > bad_equity)

class TestBrainBets(unittest.TestCase):
    """Checks the predefined bets"""
    def setUp(self):
        bot = MockBot()
        self.brain = Brain(bot)
        d = MockData()
        d.big_blind = 20
        d.pot = 130
        self.brain.data = d

    def verify_bet(self, bet, bottom, top):
        self.assertTrue(bet >= bottom)
        self.assertTrue(bet <= top)

    def test_big_raise(self):
        """Tests the big bet range"""
        bet = self.brain.big_raise()
        pot = self.brain.data.pot
        self.verify_bet(bet, pot * 0.7, pot * 1.5)

    def test_minimum_bet(self):
        """Tests the minimum bet range"""
        bb = self.brain.data.big_blind
        bet = self.brain.minimum_bet()
        self.verify_bet(bet, bb * 2, bb * 4)

class BettingFunctionalTests(BrainTest):
    """End-to-end tests with cards and everything"""
    def test_preflop_betting(self):
        """Sanity test of the preflop betting"""
        bot = MockBot()
        brain = Brain(bot)
        brain.data = self.data

        # 20 to call, 140 in the pot
        self.assertAlmostEqual(brain.pot_odds(), 100 * 2.0/(14 + 2))
        brain.do_turn('bot_0', 1000)
        self.assertTrue(bot.raise_amount > 0) # shouldn't fold with a pair of aces

    def test_river_betting(self):
        """Sanity tests of betting with common cards"""
        self.data.table_cards = [Card(C.ACE, C.SPADES),
                                 Card(2, C.DIAMONDS),
                                 Card(7, C.SPADES)]
        bot = MockBot()
        brain = Brain(bot)
        brain.data = self.data
        brain.iterations = 100 # smaller for unit tests
        brain.do_turn('bot_0', 500)
        self.assertTrue(bot.raise_amount > 0)

    def test_timing_out(self):
        """Sanity tests of betting with common cards"""
        self.data.table_cards = [Card(C.ACE, C.SPADES),
                                 Card(2, C.DIAMONDS),
                                 Card(7, C.SPADES)]
        bot = MockBot()
        brain = Brain(bot)
        brain.data = self.data
        brain.iterations = 5000 # will time out
        with Timer() as t:
            brain.do_turn('bot_0', 250)
            self.assertTrue(bot.raise_amount > 0)
        self.assertTrue(t.secs < 0.250)
        self.fail()

class MockBot(object):
    """For testing the brain by itself"""
    def __init__(self):
        self.bet_amount = 0

    def set_up_parser(self, a, b):
        return None

    def call(self, amount):
        self.bet_amount = amount

    def bet(self, amount):
        self.raise_amount = amount

    def log(self, msg):
        print msg

class MockData(object):
    pass

if __name__ == '__main__':
    unittest.main()
<commit_msg>removed extra fail...<commit_after>import unittest
from pokeher.wiring import BufferPokerBot
from pokeher.theaigame import TheAiGameParserDelegate, TheAiGameActionDelegate
from pokeher.brain import Brain
from pokeher.cards import Card, Hand
from pokeher.timer import Timer
import pokeher.constants as C

class BrainTestBot(BufferPokerBot, TheAiGameParserDelegate, TheAiGameActionDelegate):
    def add_brain(self):
        self.brain = Brain(self)

    def log(self, msg):
        pass

class BrainTest(unittest.TestCase):
    def setUp(self):
        self.fake_in = []
        self.fake_out = []
        self.fake_log = []
        self.data = MockData()
        self.data.to_call = 20
        self.data.pot = 140
        self.data.hand = Hand(Card(C.ACE, C.DIAMONDS), Card(C.ACE, C.HEARTS))
        self.data.table_cards = []
        self.data.me = 'bot_0'
        self.data.bets = {}

    def test_got_output(self):
        """Tests that the bot does something when it hits the turn marker"""
        self.fake_in = ['Settings your_bot bot_0',
                        'bot_0 hand [Ac,As]',
                        'Action bot_0 5000']
        bot = BrainTestBot(self.fake_in, self.fake_out, self.fake_log)
        bot.run()

        self.assertEqual(bot.brain.data.me, 'bot_0')
        self.assertTrue(bot.brain.data.hand)
        self.assertTrue(self.fake_out)

    def test_preflop_equity_loaded(self):
        """Tests that the preflop equity data loaded correctly"""
        bot = BrainTestBot(self.fake_in, self.fake_out, self.fake_log)
        self.assertTrue(bot.brain.preflop_equity)
        self.assertEqual(len(bot.brain.preflop_equity.keys()), 1326)

    def test_preflop_sanity(self):
        """Pull some stuff from the preflop equity and spot check it"""
        bot = BrainTestBot(self.fake_in, self.fake_out, self.fake_log)
        bad_hand = Hand(Card(2, C.CLUBS), Card(3, C.DIAMONDS))
        sample_key = repr(bad_hand)

        self.assertTrue(sample_key in bot.brain.preflop_equity.keys())
        bad_equity = bot.brain.preflop_equity[sample_key]
        self.assertTrue(bad_equity > 0.2)

        good_hand = Hand(Card(C.ACE, C.SPADES), Card(C.ACE, C.DIAMONDS))
        good_equity = bot.brain.preflop_equity[repr(good_hand)]
        self.assertTrue(good_equity > bad_equity)

class TestBrainBets(unittest.TestCase):
    """Checks the predefined bets"""
    def setUp(self):
        bot = MockBot()
        self.brain = Brain(bot)
        d = MockData()
        d.big_blind = 20
        d.pot = 130
        self.brain.data = d

    def verify_bet(self, bet, bottom, top):
        self.assertTrue(bet >= bottom)
        self.assertTrue(bet <= top)

    def test_big_raise(self):
        """Tests the big bet range"""
        bet = self.brain.big_raise()
        pot = self.brain.data.pot
        self.verify_bet(bet, pot * 0.7, pot * 1.5)

    def test_minimum_bet(self):
        """Tests the minimum bet range"""
        bb = self.brain.data.big_blind
        bet = self.brain.minimum_bet()
        self.verify_bet(bet, bb * 2, bb * 4)

class BettingFunctionalTests(BrainTest):
    """End-to-end tests with cards and everything"""
    def test_preflop_betting(self):
        """Sanity test of the preflop betting"""
        bot = MockBot()
        brain = Brain(bot)
        brain.data = self.data

        # 20 to call, 140 in the pot
        self.assertAlmostEqual(brain.pot_odds(), 100 * 2.0/(14 + 2))
        brain.do_turn('bot_0', 1000)
        self.assertTrue(bot.raise_amount > 0) # shouldn't fold with a pair of aces

    def test_river_betting(self):
        """Sanity tests of betting with common cards"""
        self.data.table_cards = [Card(C.ACE, C.SPADES),
                                 Card(2, C.DIAMONDS),
                                 Card(7, C.SPADES)]
        bot = MockBot()
        brain = Brain(bot)
        brain.data = self.data
        brain.iterations = 100 # smaller for unit tests
        brain.do_turn('bot_0', 500)
        self.assertTrue(bot.raise_amount > 0)

    def test_timing_out(self):
        """Sanity tests of betting with common cards"""
        self.data.table_cards = [Card(C.ACE, C.SPADES),
                                 Card(2, C.DIAMONDS),
                                 Card(7, C.SPADES)]
        bot = MockBot()
        brain = Brain(bot)
        brain.data = self.data
        brain.iterations = 5000 # will time out
        with Timer() as t:
            brain.do_turn('bot_0', 250)
            self.assertTrue(bot.raise_amount > 0)
        self.assertTrue(t.secs < 0.250)

class MockBot(object):
    """For testing the brain by itself"""
    def __init__(self):
        self.bet_amount = 0

    def set_up_parser(self, a, b):
        return None

    def call(self, amount):
        self.bet_amount = amount

    def bet(self, amount):
        self.raise_amount = amount

    def log(self, msg):
        print msg

class MockData(object):
    pass

if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before>from .reviewsapi import ReviewsAPI

class Assigner:

    def __init__(self):
        self.reviewsapi = ReviewsAPI()

    def certifications(self):
        response = self.reviewsapi.certifications()
        return [item['project_id'] for item in response if item['status'] == 'certified']

    def projects_with_languages(self, certifications_list):
        languages_list = self.reviewsapi.certified_languages()
        projects_list = [{'project_id': project_id, 'language': language} for project_id in certifications_list for language in languages_list]

        return {'projects': projects_list}
<commit_msg>Improve names to reduce line size<commit_after>from .reviewsapi import ReviewsAPI

class Assigner:

    def __init__(self):
        self.reviewsapi = ReviewsAPI()

    def certifications(self):
        response = self.reviewsapi.certifications()
        return [item['project_id'] for item in response if item['status'] == 'certified']

    def projects_with_languages(self, certifications):
        languages = self.reviewsapi.certified_languages()
        projects = [{'project_id': project_id, 'language': language} for project_id in certifications for language in languages]

        return {'projects': projects}
<|endoftext|>


<commit_before># Copyright (C) 2015 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os.path
import sys  # noqa making sure its available for monkey patching
from unittest import skip

import fixtures
import mock

from nodepool.cmd import nodepoolcmd
from nodepool import tests
from nodepool import zk

class TestNodepoolCMD(tests.DBTestCase):
    def patch_argv(self, *args):
        argv = ["nodepool", "-s", self.secure_conf]
        argv.extend(args)
        self.useFixture(fixtures.MonkeyPatch('sys.argv', argv))

    def assert_listed(self, configfile, cmd, col, val, count):
        log = logging.getLogger("tests.PrettyTableMock")
        self.patch_argv("-c", configfile, *cmd)
        with mock.patch('prettytable.PrettyTable.add_row') as m_add_row:
            nodepoolcmd.main()
            rows_with_val = 0
            # Find add_rows with the status were looking for
            for args, kwargs in m_add_row.call_args_list:
                row = args[0]
                log.debug(row)
                if row[col] == val:
                    rows_with_val += 1
            self.assertEquals(rows_with_val, count)

    def assert_images_listed(self, configfile, image_cnt, status="ready"):
        self.assert_listed(configfile, ['image-list'], 6, status, image_cnt)

    def assert_nodes_listed(self, configfile, node_cnt, status="ready"):
        self.assert_listed(configfile, ['list'], 10, status, node_cnt)

    def test_image_list_empty(self):
        self.assert_images_listed(self.setup_config("node_cmd.yaml"), 0)

    def test_image_delete_invalid(self):
        configfile = self.setup_config("node_cmd.yaml")
        self.patch_argv("-c", configfile, "image-delete",
                        "--provider", "invalid-provider",
                        "--image", "invalid-image",
                        "--build-id", "invalid-build-id",
                        "--upload-id", "invalid-upload-id")
        nodepoolcmd.main()

    def test_image_delete(self):
        configfile = self.setup_config("node.yaml")
        self._useBuilder(configfile)
        self.waitForImage('fake-provider', 'fake-image')
        image = self.zk.getMostRecentImageUpload('fake-image', 'fake-provider')
        self.patch_argv("-c", configfile, "image-delete",
                        "--provider", "fake-provider",
                        "--image", "fake-image",
                        "--build-id", image.build_id,
                        "--upload-id", image.id)
        nodepoolcmd.main()
        self.waitForImageDeletion('fake-provider', 'fake-image')

    @skip("Skipping until ZooKeeper is enabled")
    def test_alien_list_fail(self):
        def fail_list(self):
            raise RuntimeError('Fake list error')
        self.useFixture(fixtures.MonkeyPatch(
            'nodepool.fakeprovider.FakeOpenStackCloud.list_servers',
            fail_list))

        configfile = self.setup_config("node_cmd.yaml")
        self.patch_argv("-c", configfile, "alien-list")
        nodepoolcmd.main()

    @skip("Skipping until ZooKeeper is enabled")
    def test_alien_image_list_fail(self):
        def fail_list(self):
            raise RuntimeError('Fake list error')
        self.useFixture(fixtures.MonkeyPatch(
            'nodepool.fakeprovider.FakeOpenStackCloud.list_servers',
            fail_list))

        configfile = self.setup_config("node_cmd.yaml")
        self.patch_argv("-c", configfile, "alien-image-list")
        nodepoolcmd.main()

    @skip("Skipping until ZooKeeper is enabled")
    def test_list_nodes(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        self.assert_nodes_listed(configfile, 1)

    def test_config_validate(self):
        config = os.path.join(os.path.dirname(tests.__file__),
                              'fixtures', 'config_validate', 'good.yaml')
        self.patch_argv('-c', config, 'config-validate')
        nodepoolcmd.main()

    def test_dib_image_list(self):
        configfile = self.setup_config('node.yaml')
        self._useBuilder(configfile)
        self.waitForImage('fake-provider', 'fake-image')
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 1)

    def test_dib_image_delete(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        self._useBuilder(configfile)
        pool.start()
        self.waitForImage('fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Check the image exists
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 1)
        builds = self.zk.getMostRecentBuilds(1, 'fake-image', zk.READY)
        # Delete the image
        self.patch_argv('-c', configfile, 'dib-image-delete',
                        'fake-image-%s' % (builds[0].id))
        nodepoolcmd.main()
        self.waitForBuildDeletion('fake-image', '0000000001')
        # Check that fake-image-0000000001 doesn't exist
        self.assert_listed(
            configfile, ['dib-image-list'], 0, 'fake-image-0000000001', 0)

    @skip("Skipping until ZooKeeper is enabled")
    def test_hold(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Assert one node exists and it is node 1 in a ready state.
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, zk.READY)
        # Hold node 1
        self.patch_argv('-c', configfile, 'hold', '1')
        nodepoolcmd.main()
        # Assert the state changed to HOLD
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, 'hold')

    @skip("Skipping until ZooKeeper is enabled")
    def test_delete(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Assert one node exists and it is node 1 in a ready state.
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, zk.READY)
        # Delete node 1
        self.assert_listed(configfile, ['delete', '1'], 10, 'delete', 1)

    @skip("Skipping until ZooKeeper is enabled")
    def test_delete_now(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Assert one node exists and it is node 1 in a ready state.
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, zk.READY)
        # Delete node 1
        self.patch_argv('-c', configfile, 'delete', '--now', '1')
        nodepoolcmd.main()
        # Assert the node is gone
        self.assert_listed(configfile, ['list'], 0, 1, 0)

    def test_image_build(self):
        configfile = self.setup_config('node.yaml')
        self._useBuilder(configfile)

        # wait for the scheduled build to arrive
        self.waitForImage('fake-provider', 'fake-image')
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 1)
        image = self.zk.getMostRecentImageUpload('fake-image', 'fake-provider')

        # now do the manual build request
        self.patch_argv("-c", configfile, "image-build", "fake-image")
        nodepoolcmd.main()

        self.waitForImage('fake-provider', 'fake-image', [image])
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 2)

    def test_job_create(self):
        configfile = self.setup_config('node.yaml')
        self.patch_argv("-c", configfile, "job-create", "fake-job",
                        "--hold-on-failure", "1")
        nodepoolcmd.main()
        self.assert_listed(configfile, ['job-list'], 2, 1, 1)

    def test_job_delete(self):
        configfile = self.setup_config('node.yaml')
        self.patch_argv("-c", configfile, "job-create", "fake-job",
                        "--hold-on-failure", "1")
        nodepoolcmd.main()
        self.assert_listed(configfile, ['job-list'], 2, 1, 1)
        self.patch_argv("-c", configfile, "job-delete", "1")
        nodepoolcmd.main()
        self.assert_listed(configfile, ['job-list'], 0, 1, 0)
<commit_msg>Re-enable test: test_alien_list_fail<commit_after># Copyright (C) 2015 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os.path
import sys  # noqa making sure its available for monkey patching
from unittest import skip

import fixtures
import mock

from nodepool.cmd import nodepoolcmd
from nodepool import tests
from nodepool import zk

class TestNodepoolCMD(tests.DBTestCase):
    def patch_argv(self, *args):
        argv = ["nodepool", "-s", self.secure_conf]
        argv.extend(args)
        self.useFixture(fixtures.MonkeyPatch('sys.argv', argv))

    def assert_listed(self, configfile, cmd, col, val, count):
        log = logging.getLogger("tests.PrettyTableMock")
        self.patch_argv("-c", configfile, *cmd)
        with mock.patch('prettytable.PrettyTable.add_row') as m_add_row:
            nodepoolcmd.main()
            rows_with_val = 0
            # Find add_rows with the status were looking for
            for args, kwargs in m_add_row.call_args_list:
                row = args[0]
                log.debug(row)
                if row[col] == val:
                    rows_with_val += 1
            self.assertEquals(rows_with_val, count)

    def assert_images_listed(self, configfile, image_cnt, status="ready"):
        self.assert_listed(configfile, ['image-list'], 6, status, image_cnt)

    def assert_nodes_listed(self, configfile, node_cnt, status="ready"):
        self.assert_listed(configfile, ['list'], 10, status, node_cnt)

    def test_image_list_empty(self):
        self.assert_images_listed(self.setup_config("node_cmd.yaml"), 0)

    def test_image_delete_invalid(self):
        configfile = self.setup_config("node_cmd.yaml")
        self.patch_argv("-c", configfile, "image-delete",
                        "--provider", "invalid-provider",
                        "--image", "invalid-image",
                        "--build-id", "invalid-build-id",
                        "--upload-id", "invalid-upload-id")
        nodepoolcmd.main()

    def test_image_delete(self):
        configfile = self.setup_config("node.yaml")
        self._useBuilder(configfile)
        self.waitForImage('fake-provider', 'fake-image')
        image = self.zk.getMostRecentImageUpload('fake-image', 'fake-provider')
        self.patch_argv("-c", configfile, "image-delete",
                        "--provider", "fake-provider",
                        "--image", "fake-image",
                        "--build-id", image.build_id,
                        "--upload-id", image.id)
        nodepoolcmd.main()
        self.waitForImageDeletion('fake-provider', 'fake-image')

    def test_alien_list_fail(self):
        def fail_list(self):
            raise RuntimeError('Fake list error')
        self.useFixture(fixtures.MonkeyPatch(
            'nodepool.fakeprovider.FakeOpenStackCloud.list_servers',
            fail_list))

        configfile = self.setup_config("node_cmd.yaml")
        self.patch_argv("-c", configfile, "alien-list")
        nodepoolcmd.main()

    @skip("Skipping until ZooKeeper is enabled")
    def test_alien_image_list_fail(self):
        def fail_list(self):
            raise RuntimeError('Fake list error')
        self.useFixture(fixtures.MonkeyPatch(
            'nodepool.fakeprovider.FakeOpenStackCloud.list_servers',
            fail_list))

        configfile = self.setup_config("node_cmd.yaml")
        self.patch_argv("-c", configfile, "alien-image-list")
        nodepoolcmd.main()

    @skip("Skipping until ZooKeeper is enabled")
    def test_list_nodes(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        self.assert_nodes_listed(configfile, 1)

    def test_config_validate(self):
        config = os.path.join(os.path.dirname(tests.__file__),
                              'fixtures', 'config_validate', 'good.yaml')
        self.patch_argv('-c', config, 'config-validate')
        nodepoolcmd.main()

    def test_dib_image_list(self):
        configfile = self.setup_config('node.yaml')
        self._useBuilder(configfile)
        self.waitForImage('fake-provider', 'fake-image')
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 1)

    def test_dib_image_delete(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        self._useBuilder(configfile)
        pool.start()
        self.waitForImage('fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Check the image exists
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 1)
        builds = self.zk.getMostRecentBuilds(1, 'fake-image', zk.READY)
        # Delete the image
        self.patch_argv('-c', configfile, 'dib-image-delete',
                        'fake-image-%s' % (builds[0].id))
        nodepoolcmd.main()
        self.waitForBuildDeletion('fake-image', '0000000001')
        # Check that fake-image-0000000001 doesn't exist
        self.assert_listed(
            configfile, ['dib-image-list'], 0, 'fake-image-0000000001', 0)

    @skip("Skipping until ZooKeeper is enabled")
    def test_hold(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Assert one node exists and it is node 1 in a ready state.
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, zk.READY)
        # Hold node 1
        self.patch_argv('-c', configfile, 'hold', '1')
        nodepoolcmd.main()
        # Assert the state changed to HOLD
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, 'hold')

    @skip("Skipping until ZooKeeper is enabled")
    def test_delete(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Assert one node exists and it is node 1 in a ready state.
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, zk.READY)
        # Delete node 1
        self.assert_listed(configfile, ['delete', '1'], 10, 'delete', 1)

    @skip("Skipping until ZooKeeper is enabled")
    def test_delete_now(self):
        configfile = self.setup_config('node.yaml')
        pool = self.useNodepool(configfile, watermark_sleep=1)
        pool.start()
        self.waitForImage(pool, 'fake-provider', 'fake-image')
        self.waitForNodes(pool)
        # Assert one node exists and it is node 1 in a ready state.
        self.assert_listed(configfile, ['list'], 0, 1, 1)
        self.assert_nodes_listed(configfile, 1, zk.READY)
        # Delete node 1
        self.patch_argv('-c', configfile, 'delete', '--now', '1')
        nodepoolcmd.main()
        # Assert the node is gone
        self.assert_listed(configfile, ['list'], 0, 1, 0)

    def test_image_build(self):
        configfile = self.setup_config('node.yaml')
        self._useBuilder(configfile)

        # wait for the scheduled build to arrive
        self.waitForImage('fake-provider', 'fake-image')
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 1)
        image = self.zk.getMostRecentImageUpload('fake-image', 'fake-provider')

        # now do the manual build request
        self.patch_argv("-c", configfile, "image-build", "fake-image")
        nodepoolcmd.main()

        self.waitForImage('fake-provider', 'fake-image', [image])
        self.assert_listed(configfile, ['dib-image-list'], 4, zk.READY, 2)

    def test_job_create(self):
        configfile = self.setup_config('node.yaml')
        self.patch_argv("-c", configfile, "job-create", "fake-job",
                        "--hold-on-failure", "1")
        nodepoolcmd.main()
        self.assert_listed(configfile, ['job-list'], 2, 1, 1)

    def test_job_delete(self):
        configfile = self.setup_config('node.yaml')
        self.patch_argv("-c", configfile, "job-create", "fake-job",
                        "--hold-on-failure", "1")
        nodepoolcmd.main()
        self.assert_listed(configfile, ['job-list'], 2, 1, 1)
        self.patch_argv("-c", configfile, "job-delete", "1")
        nodepoolcmd.main()
        self.assert_listed(configfile, ['job-list'], 0, 1, 0)
<|endoftext|>


<commit_before>from collections import OrderedDict
from arches.app.datatypes.datatypes import DataTypeFactory
from arches.app.models import models

RESOURCE_ID_KEY = "@resource_id"
NODE_ID_KEY = "@node_id"
TILE_ID_KEY = "@tile_id"

NON_DATA_COLLECTING_NODE = "NON_DATA_COLLECTING_NODE"

class LabelBasedNode(object):
    def __init__(self, name, node_id, tile_id, value, cardinality=None):
        self.name = name
        self.node_id = node_id
        self.tile_id = tile_id
        self.cardinality = cardinality
        self.value = value
        self.child_nodes = []

    def is_empty(self):
        is_empty = True

        if self.value and self.value is not NON_DATA_COLLECTING_NODE:
            is_empty = False
        else:
            for child_node in self.child_nodes:
                if not child_node.is_empty():
                    is_empty = False

        return is_empty

    def as_json(self, compact=False, include_empty_nodes=True):
        display_data = {}

        for child_node in self.child_nodes:
            formatted_node = child_node.as_json(compact=compact, include_empty_nodes=include_empty_nodes)

            formatted_node_name, formatted_node_value = formatted_node.popitem()

            if include_empty_nodes or not child_node.is_empty():
                previous_val = display_data.get(formatted_node_name)
                cardinality = child_node.cardinality

                # let's handle multiple identical node names
                if not previous_val:
                    should_create_new_array = cardinality == "n" and self.tile_id != child_node.tile_id
                    display_data[formatted_node_name] = [formatted_node_value] if should_create_new_array else formatted_node_value
                elif isinstance(previous_val, list):
                    display_data[formatted_node_name].append(formatted_node_value)
                else:
                    display_data[formatted_node_name] = [previous_val, formatted_node_value]

        val = self.value
        if compact and display_data:
            if self.value is not NON_DATA_COLLECTING_NODE:
                if self.value is not None:
                    display_data.update(self.value)
        elif compact and not display_data:  # if compact and no child nodes
            display_data = self.value
        elif not compact:
            display_data[NODE_ID_KEY] = self.node_id
            display_data[TILE_ID_KEY] = self.tile_id
            if self.value is not None and self.value is not NON_DATA_COLLECTING_NODE:
                display_data.update(self.value)

        return {self.name: display_data}

class LabelBasedGraph(object):
    @staticmethod
    def generate_node_ids_to_tiles_reference_and_nodegroup_cardinality_reference(resource):
        """
        Builds a reference of all nodes in a in a given resource,
        paired with a list of tiles in which they exist
        """
        node_ids_to_tiles_reference = {}
        nodegroupids = set()

        for tile in resource.tiles:
            nodegroupids.add(str(tile.nodegroup_id))
            node_ids = list(tile.data.keys())

            if str(tile.nodegroup_id) not in node_ids:
                node_ids.append(str(tile.nodegroup_id))

            for node_id in node_ids:
                tile_list = node_ids_to_tiles_reference.get(node_id, [])
                tile_list.append(tile)
                node_ids_to_tiles_reference[node_id] = tile_list

        nodegroup_cardinality = models.NodeGroup.objects.filter(pk__in=nodegroupids).values("nodegroupid", "cardinality")
        nodegroup_cardinality_reference = {str(nodegroup["nodegroupid"]): nodegroup["cardinality"] for nodegroup in nodegroup_cardinality}

        return node_ids_to_tiles_reference, nodegroup_cardinality_reference

    @classmethod
    def from_tile(
        cls,
        tile,
        node_ids_to_tiles_reference,
        nodegroup_cardinality_reference=None,
        datatype_factory=None,
        node_cache=None,
        compact=False,
        hide_empty_nodes=False,
        as_json=True,
    ):
        """
        Generates a label-based graph from a given tile
        """
        if not datatype_factory:
            datatype_factory = DataTypeFactory()

        if node_cache is None:  # need explicit None comparison
            node_cache = {}

        nodegroup_id = tile.nodegroup_id

        node = node_cache.get(nodegroup_id)
        if not node:
            node = models.Node.objects.get(pk=nodegroup_id)
            node_cache[nodegroup_id] = node

        graph = cls._build_graph(
            input_node=node,
            input_tile=tile,
            parent_tree=None,
            node_ids_to_tiles_reference=node_ids_to_tiles_reference,
            nodegroup_cardinality_reference=nodegroup_cardinality_reference,
            node_cache=node_cache,
            datatype_factory=datatype_factory,
        )

        return graph.as_json(include_empty_nodes=bool(not hide_empty_nodes)) if as_json else graph

    @classmethod
    def from_resource(
        cls, resource, datatype_factory=None, node_cache=None, compact=False, hide_empty_nodes=False, as_json=True, user=None, perm=None
    ):
        """
        Generates a label-based graph from a given resource
        """
        if not datatype_factory:
            datatype_factory = DataTypeFactory()

        if node_cache is None:  # need explicit None comparison
            node_cache = {}

        if not resource.tiles:
            resource.load_tiles(user, perm)

        (
            node_ids_to_tiles_reference,
            nodegroup_cardinality_reference,
        ) = cls.generate_node_ids_to_tiles_reference_and_nodegroup_cardinality_reference(resource=resource)

        root_label_based_node = LabelBasedNode(name=None, node_id=None, tile_id=None, value=None, cardinality=None)

        for tile in resource.tiles:
            label_based_graph = LabelBasedGraph.from_tile(
                tile=tile,
                node_ids_to_tiles_reference=node_ids_to_tiles_reference,
                nodegroup_cardinality_reference=nodegroup_cardinality_reference,
                datatype_factory=datatype_factory,
                node_cache=node_cache,
                compact=compact,
                hide_empty_nodes=hide_empty_nodes,
                as_json=False,
            )

            if label_based_graph:
                root_label_based_node.child_nodes.append(label_based_graph)

        if as_json:
            root_label_based_node_json = root_label_based_node.as_json(compact=compact, include_empty_nodes=bool(not hide_empty_nodes))

            _dummy_resource_name, resource_graph = root_label_based_node_json.popitem()

            # removes unneccesary ( None ) top-node values
            for key in [NODE_ID_KEY, TILE_ID_KEY]:
                resource_graph.pop(key, None)

            # adds metadata that was previously only accessible via API
            resource_graph["displaydescription"] = resource.displaydescription
            resource_graph["displayname"] = resource.displayname
            resource_graph["graph_id"] = resource.graph_id
            resource_graph["legacyid"] = resource.legacyid
            resource_graph["map_popup"] = resource.map_popup
            resource_graph["resourceinstanceid"] = resource.resourceinstanceid

            return resource_graph
        else:  # pragma: no cover
            return root_label_based_node

    @classmethod
    def from_resources(cls, resources, compact=False, hide_empty_nodes=False, as_json=True):
        """
        Generates a list of label-based graph from given resources
        """

        datatype_factory = DataTypeFactory()
        node_cache = {}

        resource_label_based_graphs = []

        for resource in resources:
            resource_label_based_graph = cls.from_resource(
                resource=resource,
                datatype_factory=datatype_factory,
                node_cache=node_cache,
                compact=compact,
                hide_empty_nodes=hide_empty_nodes,
                as_json=as_json,
            )

            resource_label_based_graph[RESOURCE_ID_KEY] = str(resource.pk)
            resource_label_based_graphs.append(resource_label_based_graph)

        return resource_label_based_graphs

    @classmethod
    def _get_display_value(cls, tile, node, datatype_factory):
        display_value = None

        # if the node is unable to collect data, let's explicitly say so
        if datatype_factory.datatypes[node.datatype].defaultwidget is None:
            display_value = NON_DATA_COLLECTING_NODE
        elif tile.data:
            datatype = datatype_factory.get_instance(node.datatype)

            # `get_display_value` varies between datatypes,
            # so let's handle errors here instead of nullguarding all models
            try:
                display_value = datatype.to_json(tile=tile, node=node)
            except:  # pragma: no cover
                pass

        return display_value

    @classmethod
    def _build_graph(
        cls, input_node, input_tile, parent_tree, node_ids_to_tiles_reference, nodegroup_cardinality_reference, node_cache, datatype_factory
    ):
        # if an input_tile doesn't have any nodes, it should associate itself
        for associated_tile in node_ids_to_tiles_reference.get(str(input_node.pk), [input_tile]):
            parent_tile = associated_tile.parenttile

            if associated_tile == input_tile or parent_tile == input_tile:
                label_based_node = LabelBasedNode(
                    name=input_node.name,
                    node_id=str(input_node.pk),
                    tile_id=str(associated_tile.pk),
                    value=cls._get_display_value(tile=associated_tile, node=input_node, datatype_factory=datatype_factory),
                    cardinality=nodegroup_cardinality_reference[str(associated_tile.nodegroup_id)],
                )

                if not parent_tree:  # if top node and
                    if not parent_tile:  # if not top node in separate card
                        parent_tree = label_based_node
                else:
                    parent_tree.child_nodes.append(label_based_node)

                for child_node in input_node.get_direct_child_nodes():
                    if not node_cache.get(child_node.pk):
                        node_cache[child_node.pk] = child_node

                    cls._build_graph(
                        input_node=child_node,
                        input_tile=associated_tile,
                        parent_tree=label_based_node,
                        node_ids_to_tiles_reference=node_ids_to_tiles_reference,
                        nodegroup_cardinality_reference=nodegroup_cardinality_reference,
                        node_cache=node_cache,
                        datatype_factory=datatype_factory,
                    )

        return parent_tree
<commit_msg>nit #7715<commit_after>from arches.app.datatypes.datatypes import DataTypeFactory
from arches.app.models import models

RESOURCE_ID_KEY = "@resource_id"
NODE_ID_KEY = "@node_id"
TILE_ID_KEY = "@tile_id"

NON_DATA_COLLECTING_NODE = "NON_DATA_COLLECTING_NODE"

class LabelBasedNode(object):
    def __init__(self, name, node_id, tile_id, value, cardinality=None):
        self.name = name
        self.node_id = node_id
        self.tile_id = tile_id
        self.cardinality = cardinality
        self.value = value
        self.child_nodes = []

    def is_empty(self):
        is_empty = True

        if self.value and self.value is not NON_DATA_COLLECTING_NODE:
            is_empty = False
        else:
            for child_node in self.child_nodes:
                if not child_node.is_empty():
                    is_empty = False

        return is_empty

    def as_json(self, compact=False, include_empty_nodes=True):
        display_data = {}

        for child_node in self.child_nodes:
            formatted_node = child_node.as_json(compact=compact, include_empty_nodes=include_empty_nodes)

            formatted_node_name, formatted_node_value = formatted_node.popitem()

            if include_empty_nodes or not child_node.is_empty():
                previous_val = display_data.get(formatted_node_name)
                cardinality = child_node.cardinality

                # let's handle multiple identical node names
                if not previous_val:
                    should_create_new_array = cardinality == "n" and self.tile_id != child_node.tile_id
                    display_data[formatted_node_name] = [formatted_node_value] if should_create_new_array else formatted_node_value
                elif isinstance(previous_val, list):
                    display_data[formatted_node_name].append(formatted_node_value)
                else:
                    display_data[formatted_node_name] = [previous_val, formatted_node_value]

        val = self.value
        if compact and display_data:
            if self.value is not NON_DATA_COLLECTING_NODE:
                if self.value is not None:
                    display_data.update(self.value)
        elif compact and not display_data:  # if compact and no child nodes
            display_data = self.value
        elif not compact:
            display_data[NODE_ID_KEY] = self.node_id
            display_data[TILE_ID_KEY] = self.tile_id
            if self.value is not None and self.value is not NON_DATA_COLLECTING_NODE:
                display_data.update(self.value)

        return {self.name: display_data}

class LabelBasedGraph(object):
    @staticmethod
    def generate_node_ids_to_tiles_reference_and_nodegroup_cardinality_reference(resource):
        """
        Builds a reference of all nodes in a in a given resource,
        paired with a list of tiles in which they exist
        """
        node_ids_to_tiles_reference = {}
        nodegroupids = set()

        for tile in resource.tiles:
            nodegroupids.add(str(tile.nodegroup_id))
            node_ids = list(tile.data.keys())

            if str(tile.nodegroup_id) not in node_ids:
                node_ids.append(str(tile.nodegroup_id))

            for node_id in node_ids:
                tile_list = node_ids_to_tiles_reference.get(node_id, [])
                tile_list.append(tile)
                node_ids_to_tiles_reference[node_id] = tile_list

        nodegroup_cardinality = models.NodeGroup.objects.filter(pk__in=nodegroupids).values("nodegroupid", "cardinality")
        nodegroup_cardinality_reference = {str(nodegroup["nodegroupid"]): nodegroup["cardinality"] for nodegroup in nodegroup_cardinality}

        return node_ids_to_tiles_reference, nodegroup_cardinality_reference

    @classmethod
    def from_tile(
        cls,
        tile,
        node_ids_to_tiles_reference,
        nodegroup_cardinality_reference=None,
        datatype_factory=None,
        node_cache=None,
        compact=False,
        hide_empty_nodes=False,
        as_json=True,
    ):
        """
        Generates a label-based graph from a given tile
        """
        if not datatype_factory:
            datatype_factory = DataTypeFactory()

        if node_cache is None:  # need explicit None comparison
            node_cache = {}

        nodegroup_id = tile.nodegroup_id

        node = node_cache.get(nodegroup_id)
        if not node:
            node = models.Node.objects.get(pk=nodegroup_id)
            node_cache[nodegroup_id] = node

        graph = cls._build_graph(
            input_node=node,
            input_tile=tile,
            parent_tree=None,
            node_ids_to_tiles_reference=node_ids_to_tiles_reference,
            nodegroup_cardinality_reference=nodegroup_cardinality_reference,
            node_cache=node_cache,
            datatype_factory=datatype_factory,
        )

        return graph.as_json(include_empty_nodes=bool(not hide_empty_nodes)) if as_json else graph

    @classmethod
    def from_resource(
        cls, resource, datatype_factory=None, node_cache=None, compact=False, hide_empty_nodes=False, as_json=True, user=None, perm=None
    ):
        """
        Generates a label-based graph from a given resource
        """
        if not datatype_factory:
            datatype_factory = DataTypeFactory()

        if node_cache is None:  # need explicit None comparison
            node_cache = {}

        if not resource.tiles:
            resource.load_tiles(user, perm)

        (
            node_ids_to_tiles_reference,
            nodegroup_cardinality_reference,
        ) = cls.generate_node_ids_to_tiles_reference_and_nodegroup_cardinality_reference(resource=resource)

        root_label_based_node = LabelBasedNode(name=None, node_id=None, tile_id=None, value=None, cardinality=None)

        for tile in resource.tiles:
            label_based_graph = LabelBasedGraph.from_tile(
                tile=tile,
                node_ids_to_tiles_reference=node_ids_to_tiles_reference,
                nodegroup_cardinality_reference=nodegroup_cardinality_reference,
                datatype_factory=datatype_factory,
                node_cache=node_cache,
                compact=compact,
                hide_empty_nodes=hide_empty_nodes,
                as_json=False,
            )

            if label_based_graph:
                root_label_based_node.child_nodes.append(label_based_graph)

        if as_json:
            root_label_based_node_json = root_label_based_node.as_json(compact=compact, include_empty_nodes=bool(not hide_empty_nodes))

            _dummy_resource_name, resource_graph = root_label_based_node_json.popitem()

            # removes unneccesary ( None ) top-node values
            for key in [NODE_ID_KEY, TILE_ID_KEY]:
                resource_graph.pop(key, None)

            # adds metadata that was previously only accessible via API
            resource_graph["displaydescription"] = resource.displaydescription
            resource_graph["displayname"] = resource.displayname
            resource_graph["graph_id"] = resource.graph_id
            resource_graph["legacyid"] = resource.legacyid
            resource_graph["map_popup"] = resource.map_popup
            resource_graph["resourceinstanceid"] = resource.resourceinstanceid

            return resource_graph
        else:  # pragma: no cover
            return root_label_based_node

    @classmethod
    def from_resources(cls, resources, compact=False, hide_empty_nodes=False, as_json=True):
        """
        Generates a list of label-based graph from given resources
        """

        datatype_factory = DataTypeFactory()
        node_cache = {}

        resource_label_based_graphs = []

        for resource in resources:
            resource_label_based_graph = cls.from_resource(
                resource=resource,
                datatype_factory=datatype_factory,
                node_cache=node_cache,
                compact=compact,
                hide_empty_nodes=hide_empty_nodes,
                as_json=as_json,
            )

            resource_label_based_graph[RESOURCE_ID_KEY] = str(resource.pk)
            resource_label_based_graphs.append(resource_label_based_graph)

        return resource_label_based_graphs

    @classmethod
    def _get_display_value(cls, tile, node, datatype_factory):
        display_value = None

        # if the node is unable to collect data, let's explicitly say so
        if datatype_factory.datatypes[node.datatype].defaultwidget is None:
            display_value = NON_DATA_COLLECTING_NODE
        elif tile.data:
            datatype = datatype_factory.get_instance(node.datatype)

            # `get_display_value` varies between datatypes,
            # so let's handle errors here instead of nullguarding all models
            try:
                display_value = datatype.to_json(tile=tile, node=node)
            except:  # pragma: no cover
                pass

        return display_value

    @classmethod
    def _build_graph(
        cls, input_node, input_tile, parent_tree, node_ids_to_tiles_reference, nodegroup_cardinality_reference, node_cache, datatype_factory
    ):
        # if an input_tile doesn't have any nodes, it should associate itself
        for associated_tile in node_ids_to_tiles_reference.get(str(input_node.pk), [input_tile]):
            parent_tile = associated_tile.parenttile

            if associated_tile == input_tile or parent_tile == input_tile:
                label_based_node = LabelBasedNode(
                    name=input_node.name,
                    node_id=str(input_node.pk),
                    tile_id=str(associated_tile.pk),
                    value=cls._get_display_value(tile=associated_tile, node=input_node, datatype_factory=datatype_factory),
                    cardinality=nodegroup_cardinality_reference[str(associated_tile.nodegroup_id)],
                )

                if not parent_tree:  # if top node and
                    if not parent_tile:  # if not top node in separate card
                        parent_tree = label_based_node
                else:
                    parent_tree.child_nodes.append(label_based_node)

                for child_node in input_node.get_direct_child_nodes():
                    if not node_cache.get(child_node.pk):
                        node_cache[child_node.pk] = child_node

                    cls._build_graph(
                        input_node=child_node,
                        input_tile=associated_tile,
                        parent_tree=label_based_node,
                        node_ids_to_tiles_reference=node_ids_to_tiles_reference,
                        nodegroup_cardinality_reference=nodegroup_cardinality_reference,
                        node_cache=node_cache,
                        datatype_factory=datatype_factory,
                    )

        return parent_tree
<|endoftext|>


<commit_before>"""
Copyright (c) 2009 Marian Tietz
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. 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.

THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
"""

"""
IRC color specifications
"""

import re
import gtk

from gettext import gettext as _

from .. import config
from ..typecheck import types

from . import code
from . import escape

from ..lib import contrast
from .. import gui

COLOR_PATTERN = "([0-9]{1,2})(,[0-9]{1,2}){0,1}.*"
COLOR_TABLE =  {
			 0: contrast.CONTRAST_COLOR_WHITE,
			 1: contrast.CONTRAST_COLOR_BLACK,
			 2: contrast.CONTRAST_COLOR_BLUE,
			 3: contrast.CONTRAST_COLOR_DARK_GREEN,
			 4: contrast.CONTRAST_COLOR_DARK_RED,
			 5: contrast.CONTRAST_COLOR_LIGHT_BROWN,
			 6: contrast.CONTRAST_COLOR_PURPLE,
			 7: contrast.CONTRAST_COLOR_ORANGE,
			 8: contrast.CONTRAST_COLOR_YELLOW,
			 9: contrast.CONTRAST_COLOR_LIGHT_GREEN,
			10: contrast.CONTRAST_COLOR_CYAN,
			11: contrast.CONTRAST_COLOR_AQUA,
			12: contrast.CONTRAST_COLOR_LIGHT_BLUE,
			13: contrast.CONTRAST_COLOR_MAGENTA,
			14: contrast.CONTRAST_COLOR_GREY,
			15: contrast.CONTRAST_COLOR_LIGHT_GREY
		}
COLOR_NAMES = {
			 0: _("white"),
			 1: _("black"),
			 2: _("blue"),
			 3: _("dark green"),
			 4: _("dark red"),
			 5: _("light brown"),
			 6: _("purple"),
			 7: _("orange"),
			 8: _("yellow"),
			 9: _("light green"),
			10: _("cyan"),
			11: _("aqua"),
			12: _("light blue"),
			13: _("magenta"),
			14: _("gray"),
			15: _("light gray")
		}

def _get_output_bg_color():
	return gui.widgets.get_object("output").get_style().base[
		gtk.STATE_NORMAL]

@types (msg = basestring)
def parse_color_codes_to_tags(msg):
	""" Parse the mIRC color format ^Cn[,m] and convert it
		to the intern handled  tag.
		Convert the numbers n and m into contrast color codes
		and use them as foreground/background.
	"""
	def get_gdk_color(ccolor):
		return contrast.contrast_render_foreground_color(
			_get_output_bg_color(), ccolor)

	last_i = -1
	count = 0 # openend

	# initialize attributes self.pattern / self.color_table
	self = code.init_function_attrs(
		parse_color_codes_to_tags,

		pattern 	= re.compile(chr(3)+COLOR_PATTERN),
		color_table = COLOR_TABLE)

	while True:
		try:
			i = msg.index(chr(3), last_i+1)
		except ValueError:
			break

		match = self.pattern.match(msg[i:i+6])

		if match:
			groups = match.groups()
			tag = "<span"

			if count != 0:
				# close the previous color
				tag = "" + tag
				count -= 1

			try:
				fg = self.color_table[int(groups[0])]
				fg = get_gdk_color(fg)
			except (KeyError, TypeError):
				fg = None
			else:
				tag += " foreground='%s'" % fg

			try:
				bg = self.color_table[int(groups[1][1:])]
				bg = get_gdk_color(bg)
			except (KeyError, TypeError):
				bg = None
			else:
				tag += " background='%s'" % bg

			tag += ">"
			skip_len = 1 + (groups[0] and len(groups[0]) or 0) \
				+ (groups[1] and len(groups[1]) or 0)
			msg = msg[:i] + tag + msg[i+skip_len:]

			count += 1

		else:
			if count > 0:
				# single ^C, if there's an open tag, close it
				msg = msg[:i] + "" + msg[i+1:]
				count -= 1

		last_i = i

	if count != 0:
		# make sure the  is closed.
		msg = msg + ""

	return msg

@types (s = basestring)
def parse_color_codes_to_markups(s):
	""" convert color codes to color markups (%C) and escape
		every % in s with %%.
	"""
	s = s.replace("%", "%%")
	return s.replace(chr(3), "%C")

@types (s = basestring)
def parse_color_markups_to_codes(s):
	""" split s for %C markups and parse the numbers following.
		After parsing, return the new string.
	"""
	s_split = escape.unescape_split("%C", s, escape_char="%")
	return chr(3).join(s_split)

@types (nick = basestring)
def get_nick_color(nick):
	"""
		Returns a static color for the nick given.
		The returned color depends on the color mapping
		set in config module.
	"""
	def pick_nick_color(colors, nick):
		return colors[sum([ord(n) for n in nick]) % len(colors)]

	if not config.get_bool("tekka","color_text"):
		return

	if not config.get_bool("colors", "nick_contrast_colors"):
		# pick a color out of the user defined list

		colors = config.get_list("colors", "nick_colors", [])
		color = pick_nick_color(colors, nick)

		return color
	else:
		# pick a contrast color

		bg_color = gui.widgets.get_object("output")\
			.get_style().base[gtk.STATE_NORMAL]
		color = pick_nick_color(contrast.colors[:-1], nick)
		r = contrast.contrast_render_foreground_color(bg_color, color)

		return r

@types (nick = basestring)
def get_text_color(nick):
	"""
		Same as color.get_nick_color but for text and defaults
		to another value (text_message)
	"""
	if not config.get_bool("tekka","color_text"):
		return

	colors = contrast.colors[:-1]
	if not colors or not config.get_bool("tekka","color_nick_text"):
		return config.get("colors","text_message","#000000")

	bg_color = gui.widgets.get_object("output").get_style().\
		base[gtk.STATE_NORMAL]

	color = colors[sum([ord(n) for n in nick]) % len(colors)]

	r = contrast.contrast_render_foreground_color(bg_color, color)
	return r

@types (text = basestring)
def strip_color_codes(text):
	""" strip all color codes (chr(3)) and the following numbers """
	l = []

	for w in text.split(chr(3)):
		new_start = 0

		# check if there's a pair of numbers or a single one
		try:
			int(w[0:2])
		except ValueError:
			try:
				int(w[0:1])
			except ValueError:
				pass
			else:
				new_start += 1
		else:
			new_start += 2

		# look for , if there was a number found before
		if new_start != 0 and w[new_start:new_start+1] == ",":
			# if a number is given, remove it including the ,
			try:
				int(w[new_start+1:new_start+3])
			except ValueError:
				try:
					int(w[new_start+1:new_start+2])
				except ValueError:
					pass
				else:
					new_start += 2
			else:
				new_start += 3

		l.append(w[new_start:])
	return "".join(l)

def colorize_message(msgtype, message):
	if not config.get_bool("tekka", "color_text"):
		return message

	else:
		return "%s" % (
					config.get("colors", "text_%s" % msgtype, "#000000"),
					message)

def get_color_by_key(key):
	if config.is_default("colors",key):
		if key == "rules_color":
			return gui.widgets.get_object("output").get_style().base[
					gtk.STATE_INSENSITIVE]
		return contrast.contrast_render_foreground_color(
			_get_output_bg_color(), int(config.get_default("colors",key)))
	return gtk.gdk.Color(config.get("colors",key))

<commit_msg>Update color code<commit_after>"""
Copyright (c) 2009 Marian Tietz
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. 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.

THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
"""

"""
IRC color specifications
"""

import re
import gtk

from gettext import gettext as _

from .. import config
from ..typecheck import types

from . import code
from . import escape

from ..lib import contrast
from .. import gui

COLOR_PATTERN = "([0-9]{1,2})(,[0-9]{1,2}){0,1}.*"
COLOR_TABLE =  {
			 0: contrast.CONTRAST_COLOR_WHITE,
			 1: contrast.CONTRAST_COLOR_BLACK,
			 2: contrast.CONTRAST_COLOR_BLUE,
			 3: contrast.CONTRAST_COLOR_DARK_GREEN,
			 4: contrast.CONTRAST_COLOR_DARK_RED,
			 5: contrast.CONTRAST_COLOR_LIGHT_BROWN,
			 6: contrast.CONTRAST_COLOR_PURPLE,
			 7: contrast.CONTRAST_COLOR_ORANGE,
			 8: contrast.CONTRAST_COLOR_YELLOW,
			 9: contrast.CONTRAST_COLOR_LIGHT_GREEN,
			10: contrast.CONTRAST_COLOR_CYAN,
			11: contrast.CONTRAST_COLOR_AQUA,
			12: contrast.CONTRAST_COLOR_LIGHT_BLUE,
			13: contrast.CONTRAST_COLOR_MAGENTA,
			14: contrast.CONTRAST_COLOR_GREY,
			15: contrast.CONTRAST_COLOR_LIGHT_GREY
		}
COLOR_NAMES = {
			 0: _("white"),
			 1: _("black"),
			 2: _("blue"),
			 3: _("dark green"),
			 4: _("dark red"),
			 5: _("light brown"),
			 6: _("purple"),
			 7: _("orange"),
			 8: _("yellow"),
			 9: _("light green"),
			10: _("cyan"),
			11: _("aqua"),
			12: _("light blue"),
			13: _("magenta"),
			14: _("gray"),
			15: _("light gray")
		}

def _get_output_bg_color():
	return gui.widgets.get_object("output").get_style().base[
		gtk.STATE_NORMAL]

def _get_output_fg_color():
	return gui.widgets.get_object("output").get_style().fg[NORMAL]

@types (msg = basestring)
def parse_color_codes_to_tags(msg):
	""" Parse the mIRC color format ^Cn[,m] and convert it
		to the intern handled  tag.
		Convert the numbers n and m into contrast color codes
		and use them as foreground/background.
	"""
	def get_gdk_color(ccolor):
		return contrast.contrast_render_foreground_color(
			_get_output_bg_color(), ccolor)

	last_i = -1
	count = 0 # openend

	# initialize attributes self.pattern / self.color_table
	self = code.init_function_attrs(
		parse_color_codes_to_tags,

		pattern 	= re.compile(chr(3)+COLOR_PATTERN),
		color_table = COLOR_TABLE)

	while True:
		try:
			i = msg.index(chr(3), last_i+1)
		except ValueError:
			break

		match = self.pattern.match(msg[i:i+6])

		if match:
			groups = match.groups()
			tag = "<span"

			if count != 0:
				# close the previous color
				tag = "" + tag
				count -= 1

			try:
				fg = self.color_table[int(groups[0])]
				fg = get_gdk_color(fg)
			except (KeyError, TypeError):
				fg = None
			else:
				tag += " foreground='%s'" % fg

			try:
				bg = self.color_table[int(groups[1][1:])]
				bg = get_gdk_color(bg)
			except (KeyError, TypeError):
				bg = None
			else:
				tag += " background='%s'" % bg

			tag += ">"
			skip_len = 1 + (groups[0] and len(groups[0]) or 0) \
				+ (groups[1] and len(groups[1]) or 0)
			msg = msg[:i] + tag + msg[i+skip_len:]

			count += 1

		else:
			if count > 0:
				# single ^C, if there's an open tag, close it
				msg = msg[:i] + "" + msg[i+1:]
				count -= 1

		last_i = i

	if count != 0:
		# make sure the  is closed.
		msg = msg + ""

	return msg

@types (s = basestring)
def parse_color_codes_to_markups(s):
	""" convert color codes to color markups (%C) and escape
		every % in s with %%.
	"""
	s = s.replace("%", "%%")
	return s.replace(chr(3), "%C")

@types (s = basestring)
def parse_color_markups_to_codes(s):
	""" split s for %C markups and parse the numbers following.
		After parsing, return the new string.
	"""
	s_split = escape.unescape_split("%C", s, escape_char="%")
	return chr(3).join(s_split)

@types (text = basestring)
def strip_color_codes(text):
	""" strip all color codes (chr(3)) and the following numbers """
	l = []

	for w in text.split(chr(3)):
		new_start = 0

		# check if there's a pair of numbers or a single one
		try:
			int(w[0:2])
		except ValueError:
			try:
				int(w[0:1])
			except ValueError:
				pass
			else:
				new_start += 1
		else:
			new_start += 2

		# look for , if there was a number found before
		if new_start != 0 and w[new_start:new_start+1] == ",":
			# if a number is given, remove it including the ,
			try:
				int(w[new_start+1:new_start+3])
			except ValueError:
				try:
					int(w[new_start+1:new_start+2])
				except ValueError:
					pass
				else:
					new_start += 2
			else:
				new_start += 3

		l.append(w[new_start:])
	return "".join(l)

# Text coloring

def get_color_by_key(key):
	""" get the configured color for the given key as GdkColor.
		The key is defined in config section "colors".

		Example: get_color_by_key("last_log") -> gtk.gdk.Color("#dddddd")

		Note that str(gtk.gdk.Color("#000")) == "#000".
	"""
	if config.is_default("colors",key):
		if key == "rules_color":
			return gui.widgets.get_object("output").get_style().base[
					gtk.STATE_INSENSITIVE]
		return contrast.contrast_render_foreground_color(
			_get_output_bg_color(), int(config.get_default("colors",key)))
	return gtk.gdk.Color(config.get("colors",key))

def get_nick_color(nick):
	"""
		Returns a static color for the nick given.
		The returned color depends on the color mapping
		set in config module.
	"""
	def pick_nick_color(colors, nick):
		return colors[sum([ord(n) for n in nick]) % len(colors)]

	if not config.get_bool("tekka","color_text"):
		return _get_output_fg_color()

	if not config.get_bool("colors", "nick_contrast_colors"):
		# pick a color out of the user defined list

		colors = config.get_list("colors", "nick_colors", [])
		color = pick_nick_color(colors, nick)

		return color
	else:
		# pick a contrast color

		bg_color = _get_output_bg_color()
		color = pick_nick_color(contrast.colors[:-1], nick)
		r = contrast.contrast_render_foreground_color(bg_color, color)

		return r

def get_text_color(nick):
	"""
		Same as color.get_nick_color but for text and defaults
		to another value (text_message)
	"""
	if not config.get_bool("tekka","color_text"):
		return _get_output_fg_color()

	colors = contrast.colors[:-1]
	if not colors or not config.get_bool("tekka","color_nick_text"):
		return get_color_by_key("text_message")

	bg_color = _get_output_bg_color()
	color = colors[sum([ord(n) for n in nick]) % len(colors)]

	r = contrast.contrast_render_foreground_color(bg_color, color)
	return r

def colorize_message(msgtype, message):
	if not config.get_bool("tekka", "color_text"):
		return message

	else:
		return "%s" % (
					get_color_by_key("text_%s" % msgtype),
					message)

<|endoftext|>