<commit_before>"""Contains evaluation function"""
import csv
import os
from abc import ABCMeta, abstractmethod
from typing import Union
import SimpleITK as sitk
import numpy as np
from miapy.evaluation.metric import IMetric, IConfusionMatrixMetric, ConfusionMatrix, ISimpleITKImageMetric, INumpyArrayMetric

class IEvaluatorWriter(metaclass=ABCMeta):
    """
    Represents an evaluator writer interface, which enables to write evaluation results.
    """

    @abstractmethod
    def write(self, data: list):
        """
        Writes the evaluation results.

        :param data: The evaluation data.
        :type data: list
        """
        raise NotImplementedError

    @abstractmethod
    def write_header(self, header: list):
        """
        Writes the evaluation header.

        :param header: The evaluation header.
        :type header: list
        """
        raise NotImplementedError

class CSVEvaluatorWriter(IEvaluatorWriter):
    """
    Represents a CSV evaluator writer.
    """

    def __init__(self, path: str):
        """
        Initializes a new instance of the CSVEvaluatorWriter class.

        :param path: The file path.
        :type path: str
        """
        super().__init__()

        self.path = path

        # check file extension
        if not self.path.lower().endswith(".csv"):
            self.path = os.path.join(self.path, ".csv")

        open(self.path, 'w', newline='')  # creates (and overrides an existing) file

    def write(self, data: list):
        """
        Writes the evaluation results.

        :param data: The evaluation data.
        :type data: list
        """

        for evaluation in data:
            self.write_line(evaluation)

    def write_header(self, header: list):
        """
        Writes the evaluation header.

        :param header: The evaluation header.
        :type header: list
        """

        self.write_line(header)

    def write_line(self, data: list):
        """
        Writes a line.

        :param data: The data.
        :type data: list
        """
        with open(self.path, 'a', newline='') as file:
            writer = csv.writer(file, delimiter=';')
            writer.writerow(data)

class ConsoleEvaluatorWriter(IEvaluatorWriter):
    """
    Represents a console evaluator writer.
    """

    def __init__(self, precision: int=3):
        """
        Initializes a new instance of the ConsoleEvaluatorWriter class.

        :param precision: The float precision.
        :type precision: int
        """
        super().__init__()

        self.header = None
        self.precision = precision

    def write(self, data: list):
        """
        Writes the evaluation results.

        :param data: The evaluation data.
        :type data: list of list, e.g. [["PATIENT1", "BACKGROUND", 0.90], ["PATIENT1", "TUMOR", "0.62"]]
        """

        # format all floats with given precision to str
        out = []
        for line in data:
            out += [val if isinstance(val, str) else "{0:.{1}f}".format(val, self.precision) for val in line]
            out += ["\n"]

        # get length for output alignment
        length = max(len(max(out, key=len)), len(max(self.header, key=len))) + 2

        print("".join("{0:>{1}}".format(val, length) for val in self.header),
              "\n",
              "".join("{0:>{1}}".format(val, length) for val in out),
              sep='', end='')

    def write_header(self, header: list):
        """
        Writes the evaluation header.

        :param header: The evaluation header.
        :type header: list of str
        """

        self.header = header

class Evaluator:
    """
    Represents a metric evaluator.

    Example usage:

    >>> evaluator = Evaluator(ConsoleEvaluatorWriter(5))
    >>> evaluator.add_writer(CSVEvaluatorWriter("/some/path/to/results.csv"))
    >>> evaluator.add_label(0, "Background")
    >>> evaluator.add_label(1, "Nerve")
    >>> evaluator.add_metric(DiceCoefficient())
    >>> evaluator.add_metric(VolumeSimilarity())
    >>> evaluator.evaluate(prediction, ground_truth, "Patient1")
    The console output would be:
              ID       LABEL        DICE     VOLSMTY
        Patient1  Background     0.99955     0.99976
        Patient1       Nerve     0.70692     0.84278
    The results.csv would contain:
    ID;LABEL;DICE;VOLSMTY
    Patient1;Background;0.999548418549;0.999757743496
    Patient1;Nerve;0.70692469107;0.842776093884
    """

    def __init__(self, writer: IEvaluatorWriter=None):
        """
        Initializes a new instance of the Evaluator class.

        :param writer: One evaluator writer.
        :type writer: IEvaluatorWriter
        """

        self.metrics = []  # list of IMetrics
        self.writers = [writer] if writer is not None else []  # list of IEvaluatorWriters
        self.labels = {}  # dictionary of label: label_str
        self.is_header_written = False

    def add_label(self, label: Union[tuple, int], description: str):
        """
        Adds a label with its description to the evaluation.

        :param label: The label or a tuple of labels that should be merged.
        :type label: Union[tuple, int]
        :param description: The label's description.
        :type description: str
        """

        self.labels[label] = description

    def add_metric(self, metric: IMetric):
        """
        Adds a metric to the evaluation.

        :param metric: The metric.
        :type metric: IMetric
        """

        self.metrics.append(metric)
        self.is_header_written = False  # header changed due to new metric

    def add_writer(self, writer: IEvaluatorWriter):
        """
        Adds a writer to the evaluation.

        :param writer: The writer.
        :type writer: IEvaluatorWriter
        """

        self.writers.append(writer)
        self.is_header_written = False  # re-write header

    def evaluate(self, image: Union[sitk.Image, np.ndarray], ground_truth: Union[sitk.Image, np.ndarray],
                 evaluation_id: str):
        """
        Evaluates the metrics on the provided image and ground truth image.

        :param image: The image.
        :type image: sitk.Image
        :param ground_truth: The ground truth image.
        :type ground_truth: sitk.Image
        :param evaluation_id: The identification.
        :type evaluation_id: str
        """

        if not self.is_header_written:
            self.write_header()

        if isinstance(image, sitk.Image):
            image = sitk.GetArrayFromImage(image)
        if isinstance(ground_truth, sitk.Image):
            ground_truth = sitk.GetArrayFromImage(ground_truth)
        image_arr = image.flatten()
        ground_truth_arr = ground_truth.flatten()

        results = []  # clear results

        for label, label_str in self.labels.items():
            label_results = [evaluation_id, label_str]

            predictions = np.zeros_like(image_arr, dtype=np.bool)
            mask = np.in1d(image_arr.ravel(), label, True).reshape(image_arr.shape)
            predictions[mask] = 1
            labels = np.zeros_like(ground_truth_arr, dtype=np.bool)
            mask = np.in1d(ground_truth_arr.ravel(), label, True).reshape(ground_truth_arr.shape)
            labels[mask] = 1

            # calculate the confusion matrix (used for most metrics)
            confusion_matrix = ConfusionMatrix(predictions, labels)

            # flag indicating whether the images have been converted for ISimpleITKImageMetric
            converted_to_image = False
            prediction_as_image = None
            ground_truth_as_image = None

            # calculate the metrics
            for param_index, metric in enumerate(self.metrics):
                if isinstance(metric, IConfusionMatrixMetric):
                    metric.confusion_matrix = confusion_matrix
                elif isinstance(metric, INumpyArrayMetric):
                    metric.ground_truth = labels.astype(np.uint8)
                    metric.segmentation = predictions.astype(np.uint8)
                elif isinstance(metric, ISimpleITKImageMetric):
                    if not converted_to_image:
                        prediction_as_image = sitk.GetImageFromArray(predictions)
                        prediction_as_image.CopyInformation(image)
                        ground_truth_as_image = sitk.GetImageFromArray(labels)
                        ground_truth_as_image.CopyInformation(labels)
                        converted_to_image = True

                    metric.ground_truth = ground_truth_as_image
                    metric.segmentation = prediction_as_image

                # todo add other metric instances

                label_results.append(metric.calculate())

            results.append(label_results)

        # write the results
        for writer in self.writers:
            writer.write(results)

    def write_header(self):
        """
        Writes the header.
        """

        header = ["ID", "LABEL"]

        for metric in self.metrics:
            header.append(str(metric))

        for writer in self.writers:
            writer.write_header(header)

        self.is_header_written = True
<commit_msg>refactor(Evaluator): simplify numpy calculations and conversion to SimpleITK<commit_after>"""Contains evaluation function"""
import csv
import os
from abc import ABCMeta, abstractmethod
from typing import Union
import SimpleITK as sitk
import numpy as np
from miapy.evaluation.metric import IMetric, IConfusionMatrixMetric, ConfusionMatrix, ISimpleITKImageMetric, INumpyArrayMetric

class IEvaluatorWriter(metaclass=ABCMeta):
    """
    Represents an evaluator writer interface, which enables to write evaluation results.
    """

    @abstractmethod
    def write(self, data: list):
        """
        Writes the evaluation results.

        :param data: The evaluation data.
        :type data: list
        """
        raise NotImplementedError

    @abstractmethod
    def write_header(self, header: list):
        """
        Writes the evaluation header.

        :param header: The evaluation header.
        :type header: list
        """
        raise NotImplementedError

class CSVEvaluatorWriter(IEvaluatorWriter):
    """
    Represents a CSV evaluator writer.
    """

    def __init__(self, path: str):
        """
        Initializes a new instance of the CSVEvaluatorWriter class.

        :param path: The file path.
        :type path: str
        """
        super().__init__()

        self.path = path

        # check file extension
        if not self.path.lower().endswith(".csv"):
            self.path = os.path.join(self.path, ".csv")

        open(self.path, 'w', newline='')  # creates (and overrides an existing) file

    def write(self, data: list):
        """
        Writes the evaluation results.

        :param data: The evaluation data.
        :type data: list
        """

        for evaluation in data:
            self.write_line(evaluation)

    def write_header(self, header: list):
        """
        Writes the evaluation header.

        :param header: The evaluation header.
        :type header: list
        """

        self.write_line(header)

    def write_line(self, data: list):
        """
        Writes a line.

        :param data: The data.
        :type data: list
        """
        with open(self.path, 'a', newline='') as file:
            writer = csv.writer(file, delimiter=';')
            writer.writerow(data)

class ConsoleEvaluatorWriter(IEvaluatorWriter):
    """
    Represents a console evaluator writer.
    """

    def __init__(self, precision: int=3):
        """
        Initializes a new instance of the ConsoleEvaluatorWriter class.

        :param precision: The float precision.
        :type precision: int
        """
        super().__init__()

        self.header = None
        self.precision = precision

    def write(self, data: list):
        """
        Writes the evaluation results.

        :param data: The evaluation data.
        :type data: list of list, e.g. [["PATIENT1", "BACKGROUND", 0.90], ["PATIENT1", "TUMOR", "0.62"]]
        """

        # format all floats with given precision to str
        out = []
        for line in data:
            out += [val if isinstance(val, str) else "{0:.{1}f}".format(val, self.precision) for val in line]
            out += ["\n"]

        # get length for output alignment
        length = max(len(max(out, key=len)), len(max(self.header, key=len))) + 2

        print("".join("{0:>{1}}".format(val, length) for val in self.header),
              "\n",
              "".join("{0:>{1}}".format(val, length) for val in out),
              sep='', end='')

    def write_header(self, header: list):
        """
        Writes the evaluation header.

        :param header: The evaluation header.
        :type header: list of str
        """

        self.header = header

class Evaluator:
    """
    Represents a metric evaluator.

    Example usage:

    >>> evaluator = Evaluator(ConsoleEvaluatorWriter(5))
    >>> evaluator.add_writer(CSVEvaluatorWriter("/some/path/to/results.csv"))
    >>> evaluator.add_label(0, "Background")
    >>> evaluator.add_label(1, "Nerve")
    >>> evaluator.add_metric(DiceCoefficient())
    >>> evaluator.add_metric(VolumeSimilarity())
    >>> evaluator.evaluate(prediction, ground_truth, "Patient1")
    The console output would be:
              ID       LABEL        DICE     VOLSMTY
        Patient1  Background     0.99955     0.99976
        Patient1       Nerve     0.70692     0.84278
    The results.csv would contain:
    ID;LABEL;DICE;VOLSMTY
    Patient1;Background;0.999548418549;0.999757743496
    Patient1;Nerve;0.70692469107;0.842776093884
    """

    def __init__(self, writer: IEvaluatorWriter=None):
        """
        Initializes a new instance of the Evaluator class.

        :param writer: One evaluator writer.
        :type writer: IEvaluatorWriter
        """

        self.metrics = []  # list of IMetrics
        self.writers = [writer] if writer is not None else []  # list of IEvaluatorWriters
        self.labels = {}  # dictionary of label: label_str
        self.is_header_written = False

    def add_label(self, label: Union[tuple, int], description: str):
        """
        Adds a label with its description to the evaluation.

        :param label: The label or a tuple of labels that should be merged.
        :type label: Union[tuple, int]
        :param description: The label's description.
        :type description: str
        """

        self.labels[label] = description

    def add_metric(self, metric: IMetric):
        """
        Adds a metric to the evaluation.

        :param metric: The metric.
        :type metric: IMetric
        """

        self.metrics.append(metric)
        self.is_header_written = False  # header changed due to new metric

    def add_writer(self, writer: IEvaluatorWriter):
        """
        Adds a writer to the evaluation.

        :param writer: The writer.
        :type writer: IEvaluatorWriter
        """

        self.writers.append(writer)
        self.is_header_written = False  # re-write header

    def evaluate(self, image: Union[sitk.Image, np.ndarray], ground_truth: Union[sitk.Image, np.ndarray],
                 evaluation_id: str):
        """Evaluates the metrics on the provided image and ground truth image.

        Args:
            image (sitk.Image): The segmented image.
            ground_truth (sitk.Image): The ground truth image.
            evaluation_id (str): The identification of the evaluation.
        """

        if not self.is_header_written:
            self.write_header()

        if isinstance(image, sitk.Image):
            image_array = sitk.GetArrayFromImage(image)
        if isinstance(ground_truth, sitk.Image):
            ground_truth_array = sitk.GetArrayFromImage(ground_truth)

        results = []  # clear results

        for label, label_str in self.labels.items():
            label_results = [evaluation_id, label_str]

            # get only current label
            predictions = np.in1d(image_array.ravel(), label, True).reshape(image_array.shape).astype(np.uint8)
            labels = np.in1d(ground_truth_array.ravel(), label, True).reshape(ground_truth_array.shape).astype(np.uint8)

            # calculate the confusion matrix for IConfusionMatrixMetric
            confusion_matrix = ConfusionMatrix(predictions, labels)

            # flag indicating whether the images have been converted for ISimpleITKImageMetric
            converted_to_image = False
            predictions_as_image = None
            labels_as_image = None

            # calculate the metrics
            for param_index, metric in enumerate(self.metrics):
                if isinstance(metric, IConfusionMatrixMetric):
                    metric.confusion_matrix = confusion_matrix
                elif isinstance(metric, INumpyArrayMetric):
                    metric.ground_truth = labels
                    metric.segmentation = predictions
                elif isinstance(metric, ISimpleITKImageMetric):
                    if not converted_to_image:
                        predictions_as_image = sitk.GetImageFromArray(predictions)
                        predictions_as_image.CopyInformation(image)
                        labels_as_image = sitk.GetImageFromArray(labels)
                        labels_as_image.CopyInformation(ground_truth)
                        converted_to_image = True

                    metric.ground_truth = labels_as_image
                    metric.segmentation = predictions_as_image

                label_results.append(metric.calculate())

            results.append(label_results)

        # write the results
        for writer in self.writers:
            writer.write(results)

    def write_header(self):
        """
        Writes the header.
        """

        header = ["ID", "LABEL"]

        for metric in self.metrics:
            header.append(str(metric))

        for writer in self.writers:
            writer.write_header(header)

        self.is_header_written = True
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#
# Copyright (c) 2016 ASMlover. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list ofconditions and the following disclaimer.
#
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materialsprovided with the
#    distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import asyncore
import errno
import heapq
import time
import traceback
import sys

AIO_MAX_CALLER_COUNT = 10
AIO_MAX_CALLER_RATIO = 0.25

aioTasks = []
aioCancelledNum = 0

def _removeCancelledTasks():
    """Remove cancelled tasks and rebuild heap."""
    aioTasks = [t for t in aioTasks if not t.cancelled]
    heapq.heapify(aioTasks)
    aioCancelledNum = 0

def _scheduler():
    """Run the schedule function due to expire soon."""
    now = time.time()
    while aioTasks and now >= aioTasks[0].timeout:
        caller = heapq.heappop(aioTasks)
        if caller.cancelled:
            aioCancelledNum -= 1
            continue
        if caller.repush:
            heapq.heappush(aioTasks, caller)
            caller.repush = False
            continue

        try:
            caller.call()
        except (KeyboardInterrupt, SystemExit, asyncore.ExitNow):
            raise
        except:
            print traceback.format_exc()

class CallerDelay(object):
    """Calls a function later."""
    def __init__(self, seconds, target, *args, **kwargs):
        """
            * seconds(int): number of seconds to deay
            * target(object): callable obejct
            * args: arguments to call it with
            * kwargs: keyword arguments to call it with; a special
              `errCaller` parameter can be passed, it's a callable
              called in case target function raise an exception.
        """
        assert callable(target), '%s is not callable.' % target
        assert sys.maxint >= seconds >= 0, '%s is not >= 0' % seconds

        self.delayTime = seconds
        self.target = target
        self.args = args
        self.kwargs = kwargs
        self.errorCallback = kwargs.pop('errCaller', None)
        self.repush = False
        self.timeout = time.time() + self.delayTime
        self.cancelled = False
        self.expired = False
        heapq.heappush(aioTasks, self)

    def __le__(self, other):
        return self.timeout <= other.timeout

    def call(self):
        assert not self.cancelled, 'Already cancelled.'
        try:
            try:
                self.target(*self.args, **self.kwargs)
            except (KeyboardInterrupt, SystemExit, asyncore.ExitNow):
                raise
            except:
                if self.errorCallback:
                    self.errorCallback()
                else:
                    raise
        finally:
            if not self.cancelled:
                self.expire()

    def reset(self):
        assert not self.cancelled, 'Already cancelled.'
        self.timeout = time.time() + self.delayTime
        self.repush = True

    def delay(self, seconds):
        assert not self.cancelled, 'Already cancelled.'
        assert sys.maxint >= seconds >= 0, '%s is not >= 0' % seconds

        self.delayTime = seconds
        newTime = time.time() + self.delayTime
        if newTime > self.timeout:
            self.timeout = newTime
            self.repush = True
        else:
            self.timeout = newTime
            heapq.heapify(aioTasks)

    def cancel(self):
        assert not self.cancelled, 'Already cancelled.'
        assert not self.expired, 'Already expired.'

        self.cancelled = True
        del self.target, self.args, self.kwargs, self.errorCallback

        aioCancelledNum += 1
        if aioCancelledNum > AIO_MAX_CALLER_COUNT and float(aioCancelledNum) / len(aioTasks) > AIO_MAX_CALLER_RATIO:
            pass

    def expire(self):
        assert not self.cancelled, 'Already cancelled.'
        assert not self.expired, 'Already expired.'
        self.expired = True
        del self.target, self.args, self.kwargs, self.errorCallback

class CallerCycle(CallerDelay):
    """Calls a function every x seconds."""
    def call(self):
        assert not self.cancelled, 'Already cancelled.'
        raised = False

        try:
            try:
                self.target(*self.args, **self.kwargs)
            except (KeyboardInterrupt, SystemExit, asyncore.ExitNow):
                raised = True
                raise
            except:
                if self.errorCallback:
                    self.errorCallback()
                else:
                    raised = True
                    raise
        finally:
            if not self.cancelled:
                if raised:
                    self.cancel()
                else:
                    self.timeout = time.time() + self.delayTime
                    heapq.heappush(aioTasks, self)

def loop(timeout=0.1, usePoll=True, map=None, count=None):
    pass
<commit_msg>chore(AsyncIo): add easy test for delay caller and cycle caller<commit_after>#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#
# Copyright (c) 2016 ASMlover. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list ofconditions and the following disclaimer.
#
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materialsprovided with the
#    distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function

import asyncore
import errno
import heapq
import time
import traceback
import sys

AIO_MAX_CALLER_COUNT = 10
AIO_MAX_CALLER_RATIO = 0.25

aioTasks = []
aioCancelledNum = 0

def _removeCancelledTasks():
    """Remove cancelled tasks and rebuild heap."""
    aioTasks = [t for t in aioTasks if not t.cancelled]
    heapq.heapify(aioTasks)
    aioCancelledNum = 0

def _scheduler():
    """Run the schedule function due to expire soon."""
    now = time.time()
    while aioTasks and now >= aioTasks[0].timeout:
        caller = heapq.heappop(aioTasks)
        if caller.cancelled:
            aioCancelledNum -= 1
            continue
        if caller.repush:
            heapq.heappush(aioTasks, caller)
            caller.repush = False
            continue

        try:
            caller.call()
        except (KeyboardInterrupt, SystemExit, asyncore.ExitNow):
            raise
        except:
            print(traceback.format_exc())

class CallerDelay(object):
    """Calls a function later."""
    def __init__(self, seconds, target, *args, **kwargs):
        """
            * seconds(int): number of seconds to deay
            * target(object): callable obejct
            * args: arguments to call it with
            * kwargs: keyword arguments to call it with; a special
              `errCaller` parameter can be passed, it's a callable
              called in case target function raise an exception.
        """
        assert callable(target), '%s is not callable.' % target
        assert sys.maxsize >= seconds >= 0, '%s is not >= 0' % seconds

        self.delayTime = seconds
        self.target = target
        self.args = args
        self.kwargs = kwargs
        self.errorCallback = kwargs.pop('errCaller', None)
        self.repush = False
        self.timeout = time.time() + self.delayTime
        self.cancelled = False
        self.expired = False
        heapq.heappush(aioTasks, self)

    def __lt__(self, other):
        return self.timeout < other.timeout

    def __le__(self, other):
        return self.timeout <= other.timeout

    def call(self):
        assert not self.cancelled, 'Already cancelled.'
        try:
            try:
                self.target(*self.args, **self.kwargs)
            except (KeyboardInterrupt, SystemExit, asyncore.ExitNow):
                raise
            except:
                if self.errorCallback:
                    self.errorCallback()
                else:
                    raise
        finally:
            if not self.cancelled:
                self.expire()

    def reset(self):
        assert not self.cancelled, 'Already cancelled.'
        self.timeout = time.time() + self.delayTime
        self.repush = True

    def delay(self, seconds):
        assert not self.cancelled, 'Already cancelled.'
        assert sys.maxint >= seconds >= 0, '%s is not >= 0' % seconds

        self.delayTime = seconds
        newTime = time.time() + self.delayTime
        if newTime > self.timeout:
            self.timeout = newTime
            self.repush = True
        else:
            self.timeout = newTime
            heapq.heapify(aioTasks)

    def cancel(self):
        assert not self.cancelled, 'Already cancelled.'
        assert not self.expired, 'Already expired.'

        self.cancelled = True
        del self.target, self.args, self.kwargs, self.errorCallback

        aioCancelledNum += 1
        if aioCancelledNum > AIO_MAX_CALLER_COUNT and float(aioCancelledNum) / len(aioTasks) > AIO_MAX_CALLER_RATIO:
            pass

    def expire(self):
        assert not self.cancelled, 'Already cancelled.'
        assert not self.expired, 'Already expired.'
        self.expired = True
        del self.target, self.args, self.kwargs, self.errorCallback

class CallerCycle(CallerDelay):
    """Calls a function every x seconds."""
    def call(self):
        assert not self.cancelled, 'Already cancelled.'
        raised = False

        try:
            try:
                self.target(*self.args, **self.kwargs)
            except (KeyboardInterrupt, SystemExit, asyncore.ExitNow):
                raised = True
                raise
            except:
                if self.errorCallback:
                    self.errorCallback()
                else:
                    raised = True
                    raise
        finally:
            if not self.cancelled:
                if raised:
                    self.cancel()
                else:
                    self.timeout = time.time() + self.delayTime
                    heapq.heappush(aioTasks, self)

def loop(timeout=0.1, usePoll=True, map=None, count=None):
    """Use this loop as replacement of the original asyncore.loop."""
    if usePoll and hasattr(asyncore.select, 'poll'):
        poller = asyncore.poll2
    else:
        poller = asyncore.poll

    if map is None:
        map = asyncore.socket_map

    if count is None:
        while (map or aioTasks):
            poller(timeout, map)
            _scheduler()
    else:
        while (map or aioTasks) and count > 0:
            poller(timeout, map)
            _scheduler()
            count -= 1

if __name__ == '__main__':
    def delayFoo():
        print('I will call after 2.5 seconds.')

    CallerDelay(2.5, delayFoo)
    # loop()

    def cycleFoo():
        print('I will call every second.')

    CallerCycle(1, cycleFoo)
    loop()
<|endoftext|>


<commit_before>"""ML-ENSEMBLE

:author: Sebastian Flennerhag
:copyright: 2017
:licence: MIT

Base functions for any parallel processing
"""

from __future__ import division, print_function

from ._fit_predict_functions import (_fit_score, _fit_ests,
                                     _construct_matrix, _predict,
                                     _predict_folds, _fit_ests_folds)
from numpy import nan
from pandas import DataFrame
from joblib import Parallel, delayed

def _pre_check_estimators(out, case_est_base_columns):
    """Returns ordered list of the names of successfully fittest estimators."""
    try:
        case_est_names, _, _ = zip(*out)
    except ValueError:
        case_est_names, _ = zip(*out)

    return [ce for ce in case_est_base_columns if ce in case_est_names]

def _construct_estimator_dict(out):
    """Returns a dictionary of fitted estimators."""
    fitted_estimators = {}
    for key, est_name, est in out:
        # Filter out unfitted models
        if est_name is not None:
            # Add key
            if key not in fitted_estimators:
                fitted_estimators[key] = []

            fitted_estimators[key].append((est_name, est))
    return fitted_estimators

def _parallel_estimation(function, data, estimator_cases,
                         optional_args=None, n_jobs=-1,
                         parallel=None, verbose=False):
    """Backend function for estimator evaluation.

    Functions used for parallel estimation must accept only on argument,
    that the function itself unpacks.

    Parameters
    ----------
    function : function
        function to be evaluated in parallel loop. Function should accept only
        one argument, a tuple for unpacking. The tuple is unpacked as one of:

            - ``data_tuple, estimator_info = tuple``
            - ``const_tuple, data_tuple, estimator_info = tuple``

        each tuple in turn can be furhter unpacked if desired:
            ``(xtrain, xtest, ytest, ytrain, p_name), (est, est_name) = tuple``

    data : list
        a list of lists, where the last element in each list is a key
        in the dict estimator_cases: ``[Xtrain [, Xtest, ytrain, ytest], key]``

    estimator_cases : dict
        dictionary that maps preprocessing cases to a list of estimators to be
        fitted on the generated data.

    optional_args : tuple
        a tuple of optional arguments to be passed to function.

    n_jobs : int
        number of CPUs to use.

    parallel : obj, None (default = None)
        parallel object to use. If several estimations are to be made in
        sequence, using the same parallel object avoids destroying and creating
        the pool of workers. If ``parallel = None``, a new pool will be
        created.

    verbose : int
        verbosity of parallel jobs.
    """
    if parallel is None:
        parallel = Parallel(n_jobs=n_jobs, verbose=verbose)

    optional_args = optional_args if optional_args is not None else tuple()

    return parallel(delayed(function)(optional_args + (tup, est))
                    for tup in data
                    for est in estimator_cases[tup[-1]])

def base_predict(data, estimator_cases, parallel, function_args,
                 folded_preds, n, columns, as_df=False, n_jobs=-1,
                 verbose=False):
    """Generate a matrix M of predictions from m estimators.

    Generic function for generating a prediction matrix M over a set of
    cases, as defined by the mapping over data and estimator cases, where
    ``data[i][-1]`` is assumed to be a key of estimator_cases.

    Parameters
    -----------
    data: list-like
        object to be passed to function for parallel estimation. Standard
        format is a nested list of inputs, i.e.
        ``[[Xtrain, Xtest, ytrain, ytest, test_idx, preprocess_case_name], ]``

    estimator_cases: dict
        dictionary that maps estimators on each preprocessing case.
        Each entry is a list of tuples, ``{'': [(est_name, est), ...], ...}``

    function_args: tuple
        a tuple of arguments passed to the evaluation function

    folded_preds: bool
        whether predictions should be generated using the ``_predict_folds``
        function. Otherwise the ``_predict`` function is used.

    n: int
        shape of test set.

    columns: list
        list of column names. Used to map prediction scores to estimators,
        and if as_df is True, to map columns headers.

    as_df: bool
        whether the output matrix M should be returned as a pandas DataFrame
        columns names correspond to the estimator that generated the
        respective predictions.

    n_jobs: int
        number of CPU cores to use for parallel estimation.

    verbose: bool, int
        degree of printed messages.

    Returns
    ---------
    M: array-like, shape=[n_samples, n_estimators]
        Matrix of estimator predations. Either a numpy array of a pandas
        Data Frame.

    fitted_estimator_names: list
        list of estimator names for estimators with successful predictions.
    """
    if folded_preds:
        function = _predict_folds
    else:
        function = _predict

    out = _parallel_estimation(function, data, estimator_cases, function_args,
                               parallel=parallel, n_jobs=n_jobs,
                               verbose=verbose)

    fitted_estimator_names = _pre_check_estimators(out, columns)
    M = _construct_matrix(out, n, fitted_estimator_names, folded_preds)

    if as_df:
        M = DataFrame(M, columns=fitted_estimator_names)

    return M, fitted_estimator_names

def fit_estimators(data, estimator_cases, y, parallel, n_jobs=-1,
                   verbose=False):
    """Function for parallelized estimator fitting.

    Parameters
    -----------
    data: obj, list-like
        object to be passed to function for parallel estimation. Standard
        format is a nested list of training inputs for each preprocessing
        case, i.e. ``[[X_preprocessed_1, preprocess_case_name_1], ]``

    y: array-like, None
        the output values to train each preprocessed input set on.
        If None, assumes data is a list of training folds.

    estimator_cases: dict
        dictionary that maps estimators on each preprocessing case.
        Each entry is a list of tuples, ``{'': [(est_name, est), ...], }``

    n_jobs: int
        number of CPU cores to use for parallel estimation.

    verbose: bool, int
        degree of printed messages.

    Returns
    ----------
    fitted_estimators: list
        list of fitted estimator instances.
    """
    if y is None:
        # Assume 'data' is structured as [[xtrain, xtest, ytrain, ytest, ...],]
        out = _parallel_estimation(_fit_ests_folds, data, estimator_cases,
                                   parallel=parallel,
                                   n_jobs=n_jobs, verbose=verbose)
    else:
        # Assume 'data' is structured as [[X, 'case_i']]
        out = _parallel_estimation(_fit_ests, data, estimator_cases, (y,),
                                   parallel=parallel,
                                   n_jobs=n_jobs, verbose=verbose)

    # Return dictionary with only successfully fitted estimators
    return _construct_estimator_dict(out)

def cross_validate(estimators, param_sets, dout, scoring, error_score=nan,
                   n_jobs=-1, verbose=False):
    """Run cross-validated grid search in parallel on pre-made folds.

    Parameters
    -----------
    estimators: dict
        Mapping of estimator names and estimators to be iterated over.

    param_sets: dict
        Mapping of parameter settings that, for each estimator, is to be
        evaluated. Hence, for some estimator named ``est``, param_sets is a
        list of of param_settings dictionaries.

    dout: list
        list of list of folds to be fitted. Assumed to be generated by
        ``process_folds``, or otherwise similarly structured.

    scoring: obj
        function used to score predictions.

    error_score: int
        error score to return when estimation fails.

    n_jobs: int
        number of CPU cores to use for parallel estimation.

    verbose: bool, int
        degree of printed messages.

    Returns
    -------
    out: list
        list of list of estimator scores and associated information.
    """
    out = Parallel(n_jobs=n_jobs, verbose=verbose)(
                   delayed(_fit_score)(est, est_name, params, scoring,
                                       tup, i, error_score)
                   for tup in dout
                   for est_name, est in estimators
                   for i, params in enumerate(param_sets[est_name]))
    return out
<commit_msg>parallel documentation<commit_after>"""ML-ENSEMBLE

:author: Sebastian Flennerhag
:copyright: 2017
:licence: MIT

Base functions for any parallel processing
"""

from __future__ import division, print_function

from ._fit_predict_functions import (_fit_score, _fit_ests,
                                     _construct_matrix, _predict,
                                     _predict_folds, _fit_ests_folds)
from numpy import nan
from pandas import DataFrame
from joblib import Parallel, delayed

def _pre_check_estimators(out, case_est_base_columns):
    """Returns ordered list of the names of successfully fittest estimators."""
    try:
        case_est_names, _, _ = zip(*out)
    except ValueError:
        case_est_names, _ = zip(*out)

    return [ce for ce in case_est_base_columns if ce in case_est_names]

def _construct_estimator_dict(out):
    """Returns a dictionary of fitted estimators."""
    fitted_estimators = {}
    for key, est_name, est in out:
        # Filter out unfitted models
        if est_name is not None:
            # Add key
            if key not in fitted_estimators:
                fitted_estimators[key] = []

            fitted_estimators[key].append((est_name, est))
    return fitted_estimators

def _parallel_estimation(function, data, estimator_cases,
                         optional_args=None, n_jobs=-1,
                         parallel=None, verbose=False):
    """Backend function for estimator evaluation.

    Functions used for parallel estimation must accept only on argument,
    that the function itself unpacks.

    Parameters
    ----------
    function : function
        function to be evaluated in parallel loop. Function should accept only
        one argument, a tuple for unpacking. The tuple is unpacked as one of:

            - ``data_tuple, estimator_info = tuple``
            - ``const_tuple, data_tuple, estimator_info = tuple``

        each tuple in turn can be furhter unpacked if desired:
            ``(xtrain, xtest, ytest, ytrain, p_name), (est, est_name) = tuple``

    data : list
        a list of lists, where the last element in each list is a key
        in the dict estimator_cases: ``[Xtrain [, Xtest, ytrain, ytest], key]``

    estimator_cases : dict
        dictionary that maps preprocessing cases to a list of estimators to be
        fitted on the generated data.

    optional_args : tuple
        a tuple of optional arguments to be passed to function.

    n_jobs : int
        number of CPUs to use.

    parallel : obj, None (default = None)
        parallel object to use. If several estimations are to be made in
        sequence, using the same parallel object avoids destroying and creating
        the pool of workers. If ``parallel = None``, a new pool will be
        created.

    verbose : int
        verbosity of parallel jobs.
    """
    if parallel is None:
        parallel = Parallel(n_jobs=n_jobs, verbose=verbose)

    optional_args = optional_args if optional_args is not None else tuple()

    return parallel(delayed(function)(optional_args + (tup, est))
                    for tup in data
                    for est in estimator_cases[tup[-1]])

def base_predict(data, estimator_cases, parallel, function_args,
                 folded_preds, n, columns, as_df=False, n_jobs=-1,
                 verbose=False):
    """Generate a matrix M of predictions from m estimators.

    Generic function for generating a prediction matrix M over a set of
    cases, as defined by the mapping over data and estimator cases, where
    ``data[i][-1]`` is assumed to be a key of estimator_cases.

    Parameters
    -----------
    data: list-like
        object to be passed to function for parallel estimation. Standard
        format is a nested list of inputs, i.e.
        ``[[Xtrain, Xtest, ytrain, ytest, test_idx, preprocess_case_name], ]``

    estimator_cases: dict
        dictionary that maps estimators on each preprocessing case.
        Each entry is a list of tuples, ``{'': [(est_name, est), ...], ...}``

    parallel : obj, None (default = None)
        parallel object to use. If several estimations are to be made in
        sequence, using the same parallel object avoids destroying and creating
        the pool of workers. If ``parallel = None``, a new pool will be
        created.

    function_args: tuple
        a tuple of arguments passed to the evaluation function

    folded_preds: bool
        whether predictions should be generated using the ``_predict_folds``
        function. Otherwise the ``_predict`` function is used.

    n: int
        shape of test set.

    columns: list
        list of column names. Used to map prediction scores to estimators,
        and if as_df is True, to map columns headers.

    as_df: bool
        whether the output matrix M should be returned as a pandas DataFrame
        columns names correspond to the estimator that generated the
        respective predictions.

    n_jobs: int
        number of CPU cores to use for parallel estimation.

    verbose: bool, int
        degree of printed messages.

    Returns
    ---------
    M: array-like, shape=[n_samples, n_estimators]
        Matrix of estimator predations. Either a numpy array of a pandas
        Data Frame.

    fitted_estimator_names: list
        list of estimator names for estimators with successful predictions.
    """
    if folded_preds:
        function = _predict_folds
    else:
        function = _predict

    out = _parallel_estimation(function, data, estimator_cases, function_args,
                               parallel=parallel, n_jobs=n_jobs,
                               verbose=verbose)

    fitted_estimator_names = _pre_check_estimators(out, columns)
    M = _construct_matrix(out, n, fitted_estimator_names, folded_preds)

    if as_df:
        M = DataFrame(M, columns=fitted_estimator_names)

    return M, fitted_estimator_names

def fit_estimators(data, estimator_cases, y, parallel, n_jobs=-1,
                   verbose=False):
    """Function for parallelized estimator fitting.

    Parameters
    -----------
    data: obj, list-like
        object to be passed to function for parallel estimation. Standard
        format is a nested list of training inputs for each preprocessing
        case, i.e. ``[[X_preprocessed_1, preprocess_case_name_1], ]``

    y: array-like, None
        the output values to train each preprocessed input set on.
        If None, assumes data is a list of training folds.

    estimator_cases: dict
        dictionary that maps estimators on each preprocessing case.
        Each entry is a list of tuples, ``{'': [(est_name, est), ...], }``

    parallel : obj, None (default = None)
        parallel object to use. If several estimations are to be made in
        sequence, using the same parallel object avoids destroying and creating
        the pool of workers. If ``parallel = None``, a new pool will be
        created.

    n_jobs: int
        number of CPU cores to use for parallel estimation.

    verbose: bool, int
        degree of printed messages.

    Returns
    ----------
    fitted_estimators: list
        list of fitted estimator instances.
    """
    if y is None:
        # Assume 'data' is structured as [[xtrain, xtest, ytrain, ytest, ...],]
        out = _parallel_estimation(_fit_ests_folds, data, estimator_cases,
                                   parallel=parallel,
                                   n_jobs=n_jobs, verbose=verbose)
    else:
        # Assume 'data' is structured as [[X, 'case_i']]
        out = _parallel_estimation(_fit_ests, data, estimator_cases, (y,),
                                   parallel=parallel,
                                   n_jobs=n_jobs, verbose=verbose)

    # Return dictionary with only successfully fitted estimators
    return _construct_estimator_dict(out)

def cross_validate(estimators, param_sets, dout, scoring, error_score=nan,
                   n_jobs=-1, verbose=False):
    """Run cross-validated grid search in parallel on pre-made folds.

    Parameters
    -----------
    estimators: dict
        Mapping of estimator names and estimators to be iterated over.

    param_sets: dict
        Mapping of parameter settings that, for each estimator, is to be
        evaluated. Hence, for some estimator named ``est``, param_sets is a
        list of of param_settings dictionaries.

    dout: list
        list of list of folds to be fitted. Assumed to be generated by
        ``process_folds``, or otherwise similarly structured.

    scoring: obj
        function used to score predictions.

    error_score: int
        error score to return when estimation fails.

    n_jobs: int
        number of CPU cores to use for parallel estimation.

    verbose: bool, int
        degree of printed messages.

    Returns
    -------
    out: list
        list of list of estimator scores and associated information.
    """
    out = Parallel(n_jobs=n_jobs, verbose=verbose)(
                   delayed(_fit_score)(est, est_name, params, scoring,
                                       tup, i, error_score)
                   for tup in dout
                   for est_name, est in estimators
                   for i, params in enumerate(param_sets[est_name]))
    return out
<|endoftext|>


<commit_before>from datetime import timedelta
from time import time
import sys

from nose.tools import assert_raises, eq_, ok_

from mockredis.tests.fixtures import setup

if sys.version_info >= (3, 0):
    long = int

class TestRedis(object):

    def setup(self):
        setup(self)

    def test_get_types(self):
        '''
        testing type conversions for set/get, hset/hget, sadd/smembers

        Python bools, lists, dicts are returned as strings by
        redis-py/redis.
        '''

        values = list([
            True,
            False,
            [1, '2'],
            {
                'a': 1,
                'b': 'c'
            },
        ])

        eq_(None, self.redis.get('key'))

        for value in values:
            self.redis.set('key', value)
            eq_(str(value).encode('utf8'),
                self.redis.get('key'))

            self.redis.hset('hkey', 'item', value)
            eq_(str(value).encode('utf8'),
                self.redis.hget('hkey', 'item'))

            self.redis.sadd('skey', value)
            eq_(set([str(value).encode('utf8')]),
                self.redis.smembers('skey'))

            self.redis.flushdb()

    def test_incr(self):
        '''
        incr, hincr when keys exist
        '''

        values = list([
            (1, b'2'),
            ('1', b'2'),
        ])

        for value in values:
            self.redis.set('key', value[0])
            self.redis.incr('key')
            eq_(value[1],
                self.redis.get('key'),
                "redis.incr")

            self.redis.hset('hkey', 'attr', value[0])
            self.redis.hincrby('hkey', 'attr')
            eq_(value[1],
                self.redis.hget('hkey', 'attr'),
                "redis.hincrby")

            self.redis.flushdb()

    def test_incr_init(self):
        '''
        incr, hincr, decr when keys do NOT exist
        '''

        self.redis.incr('key')
        eq_(b'1', self.redis.get('key'))

        self.redis.hincrby('hkey', 'attr')
        eq_(b'1', self.redis.hget('hkey', 'attr'))

        self.redis.decr('dkey')
        eq_(b'-1', self.redis.get('dkey'))

    def test_ttl(self):
        self.redis.set('key', 'key')
        self.redis.expire('key', 30)

        result = self.redis.ttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= 30)

    def test_ttl_timedelta(self):
        self.redis.set('key', 'key')
        self.redis.expire('key', timedelta(seconds=30))

        result = self.redis.ttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= 30)

    def test_ttl_when_absent(self):
        """
        Test absent ttl handling.
        """
        # redis >= 2.8.0 returns -2 if key does exist
        eq_(self.redis.ttl("invalid_key"), -2)

        # redis-py returns -1 if there is no ttl
        self.redis.set("key", "value")
        eq_(self.redis.ttl("key"), None)

    def test_ttl_no_timeout(self):
        """
        Test whether, like the redis-py lib, ttl returns None if the key has no timeout set.
        """
        self.redis.set('key', 'key')
        eq_(self.redis.ttl('key'), None)

    def test_pttl(self):
        expiration_ms = 3000
        self.redis.set('key', 'key')
        self.redis.pexpire('key', expiration_ms)

        result = self.redis.pttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= expiration_ms)

    def test_pttl_when_absent(self):
        """
        Test absent pttl handling.
        """
        # redis >= 2.8.0 returns -2 if key does exist
        eq_(self.redis.pttl("invalid_key"), -2)

        # redis-py returns -1 if there is no ttl
        self.redis.set("key", "value")
        eq_(self.redis.pttl("key"), None)

    def test_pttl_no_timeout(self):
        """
        Test whether, like the redis-py lib, pttl returns None if the key has no timeout set.
        """
        self.redis.set('key', 'key')
        eq_(self.redis.pttl('key'), None)

    def test_expireat_calculates_time(self):
        """
        test whether expireat sets the correct ttl, setting a timestamp 30s in the future
        """
        self.redis.set('key', 'key')
        self.redis.expireat('key', int(time()) + 30)

        result = self.redis.ttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= 30, "Expected {} to be less than 30".format(result))

    def test_keys(self):
        eq_([], self.redis.keys("*"))

        self.redis.set("foo", "bar")
        eq_([b"foo"], self.redis.keys("*"))
        eq_([b"foo"], self.redis.keys("foo*"))
        eq_([b"foo"], self.redis.keys("foo"))
        eq_([], self.redis.keys("bar"))

        self.redis.set("food", "bbq")
        eq_({b"foo", b"food"}, set(self.redis.keys("*")))
        eq_({b"foo", b"food"}, set(self.redis.keys("foo*")))
        eq_([b"foo"], self.redis.keys("foo"))
        eq_([b"food"], self.redis.keys("food"))
        eq_([], self.redis.keys("bar"))

    def test_keys_unicode(self):
        eq_([], self.redis.keys("*"))

        key = u"eat \U0001F370 now"
        key_as_utf8 = key.encode('utf-8')
        self.redis.set(key, "bar")
        eq_([key_as_utf8], self.redis.keys("*"))
        eq_([key_as_utf8], self.redis.keys("eat*"))
        eq_([key_as_utf8], self.redis.keys(u"eat \U0001F370*"))
        eq_([key_as_utf8], self.redis.keys(u"eat \U0001F370*".encode('utf-8')))
        eq_([], self.redis.keys(u"eat \U0001F371*"))

    def test_contains(self):
        ok_("foo" not in self.redis)
        self.redis.set("foo", "bar")
        ok_("foo" in self.redis)

    def test_getitem(self):
        with assert_raises(KeyError):
            self.redis["foo"]
        self.redis.set("foo", "bar")
        eq_(b"bar", self.redis["foo"])
        self.redis.delete("foo")
        with assert_raises(KeyError):
            self.redis["foo"]

    def test_setitem(self):
        eq_(None, self.redis.get("foo"))
        self.redis["foo"] = "bar"
        eq_(b"bar", self.redis.get("foo"))

    def test_delitem(self):
        self.redis["foo"] = "bar"
        eq_(b"bar", self.redis["foo"])
        del self.redis["foo"]
        eq_(None, self.redis.get("foo"))
        # redispy does not correctly raise KeyError here, so we don't either
        del self.redis["foo"]

    def test_rename(self):
        self.redis["foo"] = "bar"
        ok_(self.redis.rename("foo", "new_foo"))
        eq_(b"bar", self.redis.get("new_foo"))

    def test_renamenx(self):
        self.redis["foo"] = "bar"
        self.redis["foo2"] = "bar2"
        eq_(self.redis.renamenx("foo", "foo2"), 0)
        eq_(b"bar2", self.redis.get("foo2"))
        eq_(self.redis.renamenx("foo", "foo3"), 1)
        eq_(b"bar", self.redis.get("foo3"))
<commit_msg>Attempt to fix python3.2 test failure.<commit_after>from datetime import timedelta
from time import time
import sys

from nose.tools import assert_raises, eq_, ok_

from mockredis.tests.fixtures import setup

if sys.version_info >= (3, 0):
    long = int

class TestRedis(object):

    def setup(self):
        setup(self)

    def test_get_types(self):
        '''
        testing type conversions for set/get, hset/hget, sadd/smembers

        Python bools, lists, dicts are returned as strings by
        redis-py/redis.
        '''

        values = list([
            True,
            False,
            [1, '2'],
            {
                'a': 1,
                'b': 'c'
            },
        ])

        eq_(None, self.redis.get('key'))

        for value in values:
            self.redis.set('key', value)
            eq_(str(value).encode('utf8'),
                self.redis.get('key'))

            self.redis.hset('hkey', 'item', value)
            eq_(str(value).encode('utf8'),
                self.redis.hget('hkey', 'item'))

            self.redis.sadd('skey', value)
            eq_(set([str(value).encode('utf8')]),
                self.redis.smembers('skey'))

            self.redis.flushdb()

    def test_incr(self):
        '''
        incr, hincr when keys exist
        '''

        values = list([
            (1, b'2'),
            ('1', b'2'),
        ])

        for value in values:
            self.redis.set('key', value[0])
            self.redis.incr('key')
            eq_(value[1],
                self.redis.get('key'),
                "redis.incr")

            self.redis.hset('hkey', 'attr', value[0])
            self.redis.hincrby('hkey', 'attr')
            eq_(value[1],
                self.redis.hget('hkey', 'attr'),
                "redis.hincrby")

            self.redis.flushdb()

    def test_incr_init(self):
        '''
        incr, hincr, decr when keys do NOT exist
        '''

        self.redis.incr('key')
        eq_(b'1', self.redis.get('key'))

        self.redis.hincrby('hkey', 'attr')
        eq_(b'1', self.redis.hget('hkey', 'attr'))

        self.redis.decr('dkey')
        eq_(b'-1', self.redis.get('dkey'))

    def test_ttl(self):
        self.redis.set('key', 'key')
        self.redis.expire('key', 30)

        result = self.redis.ttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= 30)

    def test_ttl_timedelta(self):
        self.redis.set('key', 'key')
        self.redis.expire('key', timedelta(seconds=30))

        result = self.redis.ttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= 30)

    def test_ttl_when_absent(self):
        """
        Test absent ttl handling.
        """
        # redis >= 2.8.0 returns -2 if key does exist
        eq_(self.redis.ttl("invalid_key"), -2)

        # redis-py returns -1 if there is no ttl
        self.redis.set("key", "value")
        eq_(self.redis.ttl("key"), None)

    def test_ttl_no_timeout(self):
        """
        Test whether, like the redis-py lib, ttl returns None if the key has no timeout set.
        """
        self.redis.set('key', 'key')
        eq_(self.redis.ttl('key'), None)

    def test_pttl(self):
        expiration_ms = 3000
        self.redis.set('key', 'key')
        self.redis.pexpire('key', expiration_ms)

        result = self.redis.pttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= expiration_ms)

    def test_pttl_when_absent(self):
        """
        Test absent pttl handling.
        """
        # redis >= 2.8.0 returns -2 if key does exist
        eq_(self.redis.pttl("invalid_key"), -2)

        # redis-py returns -1 if there is no ttl
        self.redis.set("key", "value")
        eq_(self.redis.pttl("key"), None)

    def test_pttl_no_timeout(self):
        """
        Test whether, like the redis-py lib, pttl returns None if the key has no timeout set.
        """
        self.redis.set('key', 'key')
        eq_(self.redis.pttl('key'), None)

    def test_expireat_calculates_time(self):
        """
        test whether expireat sets the correct ttl, setting a timestamp 30s in the future
        """
        self.redis.set('key', 'key')
        self.redis.expireat('key', int(time()) + 30)

        result = self.redis.ttl('key')
        ok_(isinstance(result, long))
        # should be less than the timeout originally set
        ok_(result <= 30, "Expected {} to be less than 30".format(result))

    def test_keys(self):
        eq_([], self.redis.keys("*"))

        self.redis.set("foo", "bar")
        eq_([b"foo"], self.redis.keys("*"))
        eq_([b"foo"], self.redis.keys("foo*"))
        eq_([b"foo"], self.redis.keys("foo"))
        eq_([], self.redis.keys("bar"))

        self.redis.set("food", "bbq")
        eq_({b"foo", b"food"}, set(self.redis.keys("*")))
        eq_({b"foo", b"food"}, set(self.redis.keys("foo*")))
        eq_([b"foo"], self.redis.keys("foo"))
        eq_([b"food"], self.redis.keys("food"))
        eq_([], self.redis.keys("bar"))

    def test_keys_unicode(self):
        eq_([], self.redis.keys("*"))

        # This is a little backwards, but python3.2 has trouble with unicode in strings.
        key_as_utf8 = b'eat \xf0\x9f\x8d\xb0 now'
        key = key_as_utf8.decode('utf-8')
        self.redis.set(key, "bar")
        eq_([key_as_utf8], self.redis.keys("*"))
        eq_([key_as_utf8], self.redis.keys("eat*"))

        unicode_prefix = b'eat \xf0\x9f\x8d\xb0*'.decode('utf-8')
        eq_([key_as_utf8], self.redis.keys(unicode_prefix))
        eq_([key_as_utf8], self.redis.keys(unicode_prefix.encode('utf-8')))
        unicode_prefix = b'eat \xf0\x9f\x8d\xb1*'.decode('utf-8')
        eq_([], self.redis.keys(unicode_prefix))

    def test_contains(self):
        ok_("foo" not in self.redis)
        self.redis.set("foo", "bar")
        ok_("foo" in self.redis)

    def test_getitem(self):
        with assert_raises(KeyError):
            self.redis["foo"]
        self.redis.set("foo", "bar")
        eq_(b"bar", self.redis["foo"])
        self.redis.delete("foo")
        with assert_raises(KeyError):
            self.redis["foo"]

    def test_setitem(self):
        eq_(None, self.redis.get("foo"))
        self.redis["foo"] = "bar"
        eq_(b"bar", self.redis.get("foo"))

    def test_delitem(self):
        self.redis["foo"] = "bar"
        eq_(b"bar", self.redis["foo"])
        del self.redis["foo"]
        eq_(None, self.redis.get("foo"))
        # redispy does not correctly raise KeyError here, so we don't either
        del self.redis["foo"]

    def test_rename(self):
        self.redis["foo"] = "bar"
        ok_(self.redis.rename("foo", "new_foo"))
        eq_(b"bar", self.redis.get("new_foo"))

    def test_renamenx(self):
        self.redis["foo"] = "bar"
        self.redis["foo2"] = "bar2"
        eq_(self.redis.renamenx("foo", "foo2"), 0)
        eq_(b"bar2", self.redis.get("foo2"))
        eq_(self.redis.renamenx("foo", "foo3"), 1)
        eq_(b"bar", self.redis.get("foo3"))
<|endoftext|>


<commit_before># coding: utf-8
import datetime
import re
import sys

import django.utils.six as six
import pytest
from django.utils.six import text_type
from django.utils.six.moves import xmlrpc_client
from jsonrpcclient.exceptions import ReceivedErrorResponse
from jsonrpcclient.http_client import HTTPClient

from modernrpc.exceptions import RPC_INTERNAL_ERROR

def test_xmlrpc_bool(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_true()
    assert type(result) == bool
    assert result is True

def test_jsonrpc_bool(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_true()
    assert type(result) == bool
    assert result is True

def test_xmlrpc_bool_2(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_false()
    assert type(result) == bool
    assert result is False

def test_jsonrpc_bool_2(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_false()
    assert type(result) == bool
    assert result is False

def test_xmlrpc_null(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    assert c.get_null() is None

def test_jsonrpc_null(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_null()
    assert result is None

def test_xmlrpc_int(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_int()
    assert type(result) == int
    assert result == 42

def test_jsonrpc_int(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_int()
    assert type(result) == int
    assert result == 42

def test_xmlrpc_int_negative(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_negative_int()
    assert type(result) == int
    assert result == -42

def test_jsonrpc_int_negative(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_negative_int()
    assert type(result) == int
    assert result == -42

def test_xmlrpc_float(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_float()
    assert type(result) == float
    assert result == 3.14

def test_jsonrpc_float(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_float()
    assert type(result) == float
    assert result == 3.14

def test_xmlrpc_string(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_string()
    # Unlike JSON-RPC, XML-RPC always return a str. That means the result is unicode
    # in Python 3 and ASCII in Python 2. This may be addressed in the future
    assert type(result) == str
    assert result == 'abcde'

def test_jsonrpc_string(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_string()
    # Unlike XML-RPC, JSON-RPC always return a unicode string. That means the type of the result value is
    # 'unicode' in Python 2 and 'str' in python 3.
    assert type(result) == str if six.PY3 else unicode
    assert result == 'abcde'

def test_xmlrpc_input_string(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    # Python 2 : "<type 'str'>"
    # Python 3 : "<class 'str'>"
    assert re.match(r"<(class|type) 'str'>", c.get_data_type('abcd'))

def test_jsonrpc_input_string(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    # Python 2 : "<type 'str'>"
    # Python 3 : "<class 'str'>"
    # By default on Python 2, json-rpc call to this method will return 'unicode'
    # This test suite has been configured with settings.MODERNRPC_PY2_STR_TYPE = str, so
    # arguments passed to RPC methods via XML or JSON will be converted to the same type (str in that case)
    assert re.match(r"<(class|type) 'str'>", c.get_data_type('abcd'))

def test_xmlrpc_bytes(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_bytes()
    assert result == b'abcde'

def test_jsonrpc_bytes(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    if sys.version_info < (3, 0):

        # Python 2: no problem, returned result is a standard string...
        result = c.get_bytes()

        # ... but json.loads will convert that string into an unicode object
        assert type(result) == text_type
        assert result == 'abcde'

    else:

        # Python 3: JSON cannot transport a bytearray
        with pytest.raises(ReceivedErrorResponse) as excinfo:
            c.get_bytes()

        assert excinfo.value.code == RPC_INTERNAL_ERROR

def test_xmlrpc_date(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')
    result = c.get_date()

    assert isinstance(result, xmlrpc_client.DateTime)
    assert '19870602' in str(result)
    assert '08:45:00' in str(result)

def test_xmlrpc_date_2(live_server):

    try:
        # Python 3
        c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/', use_builtin_types=True)
    except TypeError:
        # Python 3
        c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/', use_datetime=True)

    result = c.get_date()

    assert isinstance(result, datetime.datetime)

    assert result.year == 1987
    assert result.month == 6
    assert result.day == 2
    assert result.hour == 8
    assert result.minute == 45
    assert result.second == 0

def test_xmlrpc_date_3(live_server):

    date = datetime.datetime(1990, 1, 1, 0, 0, 0)

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')
    result = c.get_data_type(date)

    # Python 2 : "<type 'datetime.datetime'>"
    # Python 3 : "<class 'datetime.datetime'>"
    assert re.match(r"<(class|type) 'datetime.datetime'>", result)

def test_xmlrpc_date_4(live_server):

    try:
        # Python 3
        c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/', use_builtin_types=True)
    except TypeError:
        # Python 3
        c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/', use_datetime=True)

    date = datetime.datetime(2000, 6, 3, 0, 0, 0)
    result = c.add_one_month(date)

    # JSON-RPC will transmit the input argument and the result as standard string
    assert result.year == 2000
    assert result.month == 7
    assert result.day == 4
    assert result.hour == 0
    assert result.minute == 0
    assert result.second == 0

def test_jsonrpc_date(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_date()
    # Unlike XML-RPC, JSON transport does not store value types.
    # Dates are transmitted as string in ISO 8601 format:
    assert '1987-06-02' in result
    assert '08:45:00' in result

def test_jsonrpc_date_2(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')
    date = datetime.datetime(1990, 1, 1, 0, 0, 0)

    # Since date type is not supported by JSON-RPC spec, it is transported as string
    # to the server. By default, the decoded type depends on the Python version.
    # Since this test suite has been configured with settings.MODERNRPC_PY2_STR_TYPE = str,
    # the type returned will always be 'str'

    # We have to convert date to ISO 8601, since JSON-RPC cannot serialize it
    assert re.match(r"<(class|type) 'str'>", c.get_data_type(date.isoformat()))

def test_jsonrpc_date_3(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')
    date = datetime.datetime(2000, 6, 3, 0, 0, 0)

    # We have to convert date to ISO 8601, since JSON-RPC cannot serialize it
    result = c.add_one_month(date.isoformat())

    # JSON-RPC will transmit the input argument and the result as standard string
    assert '2000-07-04' in result

def test_xmlrpc_list(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_list()
    assert type(result) == list
    assert result == [1, 2, 3, ]

def test_jsonrpc_list(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_list()
    assert type(result) == list
    assert result == [1, 2, 3, ]

def test_xmlrpc_struct(live_server):

    c = xmlrpc_client.ServerProxy(live_server.url + '/all-rpc/')

    result = c.get_struct()
    assert type(result) == dict
    assert result == {'x': 1, 'y': 2, 'z': 3, }

def test_jsonrpc_struct(live_server):

    c = HTTPClient(live_server.url + '/all-rpc/')

    result = c.get_struct()
    assert type(result) == dict
    assert result == {'x': 1, 'y': 2, 'z': 3, }
<commit_msg>Module test_types use new fixtures<commit_after># coding: utf-8
import datetime
import re

import django.utils.six as six
import pytest
from django.utils.six import text_type
from django.utils.six.moves import xmlrpc_client as python_xmlrpc
from jsonrpcclient.exceptions import ReceivedErrorResponse

from modernrpc.exceptions import RPC_INTERNAL_ERROR

def test_xmlrpc_bool(xmlrpc_client):

    result = xmlrpc_client.get_true()
    assert type(result) == bool
    assert result is True

def test_jsonrpc_bool(jsonrpc_client):

    result = jsonrpc_client.get_true()
    assert type(result) == bool
    assert result is True

def test_xmlrpc_bool_2(xmlrpc_client):

    result = xmlrpc_client.get_false()
    assert type(result) == bool
    assert result is False

def test_jsonrpc_bool_2(jsonrpc_client):

    result = jsonrpc_client.get_false()
    assert type(result) == bool
    assert result is False

def test_xmlrpc_null(xmlrpc_client):

    assert xmlrpc_client.get_null() is None

def test_jsonrpc_null(jsonrpc_client):

    result = jsonrpc_client.get_null()
    assert result is None

def test_xmlrpc_int(xmlrpc_client):

    result = xmlrpc_client.get_int()
    assert type(result) == int
    assert result == 42

def test_jsonrpc_int(jsonrpc_client):

    result = jsonrpc_client.get_int()
    assert type(result) == int
    assert result == 42

def test_xmlrpc_int_negative(xmlrpc_client):

    result = xmlrpc_client.get_negative_int()
    assert type(result) == int
    assert result == -42

def test_jsonrpc_int_negative(jsonrpc_client):

    result = jsonrpc_client.get_negative_int()
    assert type(result) == int
    assert result == -42

def test_xmlrpc_float(xmlrpc_client):

    result = xmlrpc_client.get_float()
    assert type(result) == float
    assert result == 3.14

def test_jsonrpc_float(jsonrpc_client):

    result = jsonrpc_client.get_float()
    assert type(result) == float
    assert result == 3.14

def test_xmlrpc_string(xmlrpc_client):

    result = xmlrpc_client.get_string()
    # Unlike JSON-RPC, XML-RPC always return a str. That means the result is unicode
    # in Python 3 and ASCII in Python 2. This may be addressed in the future
    assert type(result) == str
    assert result == 'abcde'

def test_jsonrpc_string(jsonrpc_client):

    result = jsonrpc_client.get_string()
    # Unlike XML-RPC, JSON-RPC always return a unicode string. That means the type of the result value is
    # 'unicode' in Python 2 and 'str' in python 3.
    assert type(result) == text_type
    assert result == 'abcde'

def test_xmlrpc_input_string(xmlrpc_client):

    # Python 2 : "<type 'str'>"
    # Python 3 : "<class 'str'>"
    assert re.match(r"<(class|type) 'str'>", xmlrpc_client.get_data_type('abcd'))

def test_jsonrpc_input_string(jsonrpc_client):

    # Python 2 : "<type 'str'>"
    # Python 3 : "<class 'str'>"
    # By default on Python 2, json-rpc call to this method will return 'unicode'
    # This test suite has been configured with settings.MODERNRPC_PY2_STR_TYPE = str, so
    # arguments passed to RPC methods via XML or JSON will be converted to the same type (str in that case)
    assert re.match(r"<(class|type) 'str'>", jsonrpc_client.get_data_type('abcd'))

def test_xmlrpc_bytes(xmlrpc_client):

    result = xmlrpc_client.get_bytes()
    assert result == b'abcde'

def test_jsonrpc_bytes(jsonrpc_client):

    if six.PY2:

        # Python 2: no problem, returned result is a standard string...
        result = jsonrpc_client.get_bytes()

        # ... but json.loads will convert that string into an unicode object
        assert type(result) == text_type
        assert result == 'abcde'

    else:

        # Python 3: JSON cannot transport a bytearray
        with pytest.raises(ReceivedErrorResponse) as excinfo:
            jsonrpc_client.get_bytes()

        assert excinfo.value.code == RPC_INTERNAL_ERROR

def test_xmlrpc_date(xmlrpc_client):

    result = xmlrpc_client.get_date()

    assert isinstance(result, xmlrpc_client.DateTime)
    assert '19870602' in str(result)
    assert '08:45:00' in str(result)

def test_xmlrpc_date_2(all_rpc_url):

    try:
        # Python 3
        client = python_xmlrpc.ServerProxy(all_rpc_url, use_builtin_types=True)
    except TypeError:
        # Python 3
        client = python_xmlrpc.ServerProxy(all_rpc_url, use_datetime=True)

    result = client.get_date()

    assert isinstance(result, datetime.datetime)

    assert result.year == 1987
    assert result.month == 6
    assert result.day == 2
    assert result.hour == 8
    assert result.minute == 45
    assert result.second == 0

def test_xmlrpc_date_3(xmlrpc_client):

    date = datetime.datetime(1990, 1, 1, 0, 0, 0)
    result = xmlrpc_client.get_data_type(date)

    # Python 2 : "<type 'datetime.datetime'>"
    # Python 3 : "<class 'datetime.datetime'>"
    assert re.match(r"<(class|type) 'datetime.datetime'>", result)

def test_xmlrpc_date_4(all_rpc_url):

    try:
        # Python 3
        client = python_xmlrpc.ServerProxy(all_rpc_url, use_builtin_types=True)
    except TypeError:
        # Python 3
        client = python_xmlrpc.ServerProxy(all_rpc_url, use_datetime=True)

    base_date = datetime.datetime(2000, 6, 3, 0, 0, 0)
    result = client.add_one_month(base_date)

    # JSON-RPC will transmit the input argument and the result as standard string
    assert result.year == 2000
    assert result.month == 7
    assert result.day == 4
    assert result.hour == 0
    assert result.minute == 0
    assert result.second == 0

def test_jsonrpc_date(jsonrpc_client):

    result = jsonrpc_client.get_date()
    # Unlike XML-RPC, JSON transport does not store value types.
    # Dates are transmitted as string in ISO 8601 format:
    assert '1987-06-02' in result
    assert '08:45:00' in result

def test_jsonrpc_date_2(jsonrpc_client):

    date = datetime.datetime(1990, 1, 1, 0, 0, 0)

    # Since date type is not supported by JSON-RPC spec, it is transported as string
    # to the server. By default, the decoded type depends on the Python version.
    # Since this test suite has been configured with settings.MODERNRPC_PY2_STR_TYPE = str,
    # the type returned will always be 'str'

    # We have to convert date to ISO 8601, since JSON-RPC cannot serialize it
    assert re.match(r"<(class|type) 'str'>", jsonrpc_client.get_data_type(date.isoformat()))

def test_jsonrpc_date_3(jsonrpc_client):

    date = datetime.datetime(2000, 6, 3, 0, 0, 0)

    # We have to convert date to ISO 8601, since JSON-RPC cannot serialize it
    result = jsonrpc_client.add_one_month(date.isoformat())

    # JSON-RPC will transmit the input argument and the result as standard string
    assert '2000-07-04' in result

def test_xmlrpc_list(xmlrpc_client):

    result = xmlrpc_client.get_list()
    assert type(result) == list
    assert result == [1, 2, 3, ]

def test_jsonrpc_list(jsonrpc_client):

    result = jsonrpc_client.get_list()
    assert type(result) == list
    assert result == [1, 2, 3, ]

def test_xmlrpc_struct(xmlrpc_client):

    result = xmlrpc_client.get_struct()
    assert type(result) == dict
    assert result == {'x': 1, 'y': 2, 'z': 3, }

def test_jsonrpc_struct(jsonrpc_client):

    result = jsonrpc_client.get_struct()
    assert type(result) == dict
    assert result == {'x': 1, 'y': 2, 'z': 3, }
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import unittest

from mock import patch
from mock import PropertyMock
from selenium_base import SeleniumTestCase

class GeneralFrontendTest(SeleniumTestCase):
    fixtures = ['functional_test_data']

    def test_menu_dropdown_on_doc_page(self):
        with patch('requests.get') as mock_response:
            # Mock the text fetched from Google Docs
            text = PropertyMock(
                return_value=(''
                              'some text'))
            type(mock_response.return_value).text = text
            url = self.live_server_url + '/docs/analyse/'
            self.browser.get(url)
            self.find_by_xpath("//a[contains(text(), 'More')]").click()
            self.assertTrue(
                self.find_by_xpath(
                    "//a[contains(text(), 'About')]").is_displayed(),
                "dropdown functionality broken at %s" % url
            )

    def test_menu_dropdown(self):
        for url in ['/ccg/03Q/',
                    '/practice/P87629/',
                    '/measure/cerazette/',
                    '/chemical/0202010D0/',
                    '/bnf/020201/',
                    '/analyse/',
                    '/measure/',
                    '/about']:
            url = self.live_server_url + url
            self.browser.get(url)
            try:
                self.find_by_xpath("//a[contains(text(), 'More')]").click()
            except AssertionError as e:
                e.args += ("at URL %s" % url,)
                raise
            self.assertTrue(
                self.find_by_xpath(
                    "//a[contains(text(), 'About')]").is_displayed(),
                "dropdown functionality broken at %s" % url
            )

    def test_message_and_action(self):
        for url in ['/ccg/03Q/',
                    '/practice/P87629/',
                    '/measure/cerazette/',
                    '/chemical/0202010D0/',
                    '/bnf/020201/',
                    '/analyse/']:
            url = self.live_server_url + url
            self.browser.get(url)
            self.find_by_xpath(
                '//button[@id="doorbell-button"]')  # Wait for button load
            try:
                el = self.find_visible_by_xpath(
                    '//button[@id="doorbell-button"]')
                el.click()
            except TypeError as e:
                e.args += ("at URL %s" % url,)
                raise

            self.assertTrue(
                self.find_by_xpath('//div[@id="doorbell"]').is_displayed(),
                "get in touch functionality broken at %s" % url
            )

    def test_drug_name_typeahead(self):
        self.browser.get(self.live_server_url + '/analyse/')
        el = self.find_by_xpath(
            '//div[@id="numIds-wrapper"]'
            '//input[@class="select2-search__field"]')
        el.send_keys("chl")
        # This should succeed; if not, the JSON dropdown-filling has not:
        self.find_by_xpath('//ul[@id="select2-numIds-results"]//li')

    def test_practice_name_typeahead(self):
        self.browser.get(self.live_server_url + '/analyse/')
        self.find_by_xpath('//span[@id="select2-org-container"]').click()
        self.find_by_xpath(
            '//li[contains(text(), "a practice or practices")]').click()
        el = self.find_by_xpath(
            '//div[@id="orgIds-container"]'
            '//input[@class="select2-search__field"]')
        el.send_keys("ains")
        # This should succeed; if not, the JSON dropdown-filling has not:
        self.find_by_xpath('//ul[@id="select2-orgIds-results"]//li')

    def test_ccg_measures_sorting(self):
        url = self.live_server_url + '/ccg/02Q/'
        self.browser.get(url)
        # The default should be sorting by percentile, then id
        self.assertEqual(self.find_by_xpath(
            "//div[@id='charts']/div[1]").get_attribute("id"),
                         'measure_cerazette')

        # Now click to sort by potential savings
        self.browser.find_element_by_xpath(
            "//button[@data-orderby='savings']").click()

        # hack: not sure of the correct way to await the element
        # being visible.
        import time
        time.sleep(1)
        self.assertEqual(self.find_by_xpath(
            "//div[@id='charts']/div[1]").get_attribute("id"),
                         'measure_keppra')

    def test_ccg_measures_tags(self):
        url = self.live_server_url + '/ccg/02Q/?tags=foobar'
        self.browser.get(url)
        # nothing is tagged foobar, so should return the text expected
        # when no measures are shown
        import time
        time.sleep(1)
        self.assertTrue(self.find_by_xpath(
            "//p[contains(text(), 'prescribed on any')]"))

    def test_ccg_measures_explore_link(self):
        url = self.live_server_url + '/ccg/02Q/'
        self.browser.get(url)
        measure = self.find_by_xpath(
            "//div[@id='measure_keppra']")
        self.assertIn(
            '/measure/keppra',
            measure.find_element_by_partial_link_text(
                "Compare all CCGs"
            ).get_attribute('href'),
        )
        self.assertIn(
            '/ccg/02Q/keppra',
            measure.find_element_by_partial_link_text(
                "Split the measure"
            ).get_attribute('href'),
        )

if __name__ == '__main__':
    unittest.main()
<commit_msg>Fix test broken in 2d6eb17<commit_after># -*- coding: utf-8 -*-
import unittest

from mock import patch
from mock import PropertyMock
from selenium_base import SeleniumTestCase

class GeneralFrontendTest(SeleniumTestCase):
    fixtures = ['functional_test_data']

    def test_menu_dropdown_on_doc_page(self):
        with patch('requests.get') as mock_response:
            # Mock the text fetched from Google Docs
            text = PropertyMock(
                return_value=(''
                              'some text'))
            type(mock_response.return_value).text = text
            url = self.live_server_url + '/docs/analyse/'
            self.browser.get(url)
            self.find_by_xpath("//a[contains(text(), 'More')]").click()
            self.assertTrue(
                self.find_by_xpath(
                    "//a[contains(text(), 'About')]").is_displayed(),
                "dropdown functionality broken at %s" % url
            )

    def test_menu_dropdown(self):
        for url in ['/ccg/03Q/',
                    '/practice/P87629/',
                    '/measure/cerazette/',
                    '/chemical/0202010D0/',
                    '/bnf/020201/',
                    '/analyse/',
                    '/measure/',
                    '/about']:
            url = self.live_server_url + url
            self.browser.get(url)
            try:
                self.find_by_xpath("//a[contains(text(), 'More')]").click()
            except AssertionError as e:
                e.args += ("at URL %s" % url,)
                raise
            self.assertTrue(
                self.find_by_xpath(
                    "//a[contains(text(), 'About')]").is_displayed(),
                "dropdown functionality broken at %s" % url
            )

    def test_message_and_action(self):
        for url in ['/ccg/03Q/',
                    '/practice/P87629/',
                    '/measure/cerazette/',
                    '/chemical/0202010D0/',
                    '/bnf/020201/',
                    '/analyse/']:
            url = self.live_server_url + url
            self.browser.get(url)
            self.find_by_xpath(
                '//button[@id="doorbell-button"]')  # Wait for button load
            try:
                el = self.find_visible_by_xpath(
                    '//button[@id="doorbell-button"]')
                el.click()
            except TypeError as e:
                e.args += ("at URL %s" % url,)
                raise

            self.assertTrue(
                self.find_by_xpath('//div[@id="doorbell"]').is_displayed(),
                "get in touch functionality broken at %s" % url
            )

    def test_drug_name_typeahead(self):
        self.browser.get(self.live_server_url + '/analyse/')
        el = self.find_by_xpath(
            '//div[@id="numIds-wrapper"]'
            '//input[@class="select2-search__field"]')
        el.send_keys("chl")
        # This should succeed; if not, the JSON dropdown-filling has not:
        self.find_by_xpath('//ul[@id="select2-numIds-results"]//li')

    def test_practice_name_typeahead(self):
        self.browser.get(self.live_server_url + '/analyse/')
        self.find_by_xpath('//span[@id="select2-org-container"]').click()
        self.find_by_xpath(
            '//li[contains(text(), "a practice or practices")]').click()
        el = self.find_by_xpath(
            '//div[@id="orgIds-container"]'
            '//input[@class="select2-search__field"]')
        el.send_keys("ains")
        # This should succeed; if not, the JSON dropdown-filling has not:
        self.find_by_xpath('//ul[@id="select2-orgIds-results"]//li')

    def test_ccg_measures_sorting(self):
        url = self.live_server_url + '/ccg/02Q/'
        self.browser.get(url)
        # The default should be sorting by percentile, then id
        self.assertEqual(self.find_by_xpath(
            "//div[@id='charts']/div[1]").get_attribute("id"),
                         'measure_cerazette')

        # Now click to sort by potential savings
        self.browser.find_element_by_xpath(
            "//button[@data-orderby='savings']").click()

        # hack: not sure of the correct way to await the element
        # being visible.
        import time
        time.sleep(1)
        self.assertEqual(self.find_by_xpath(
            "//div[@id='charts']/div[1]").get_attribute("id"),
                         'measure_keppra')

    def test_ccg_measures_tags(self):
        url = self.live_server_url + '/ccg/02Q/?tags=foobar'
        self.browser.get(url)
        # nothing is tagged foobar, so should return the text expected
        # when no measures are shown
        import time
        time.sleep(1)
        self.assertTrue(self.find_by_xpath(
            "//p[contains(text(), 'Unrecognised tag')]"))

    def test_ccg_measures_explore_link(self):
        url = self.live_server_url + '/ccg/02Q/'
        self.browser.get(url)
        measure = self.find_by_xpath(
            "//div[@id='measure_keppra']")
        self.assertIn(
            '/measure/keppra',
            measure.find_element_by_partial_link_text(
                "Compare all CCGs"
            ).get_attribute('href'),
        )
        self.assertIn(
            '/ccg/02Q/keppra',
            measure.find_element_by_partial_link_text(
                "Split the measure"
            ).get_attribute('href'),
        )

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