<commit_before>import numpy as np
from skimage import img_as_float, io, exposure, img_as_uint, color, img_as_ubyte
import matplotlib.pyplot as plt
import psyutils as pu

def guess_type(image):
    """Make an educated guess about an image's dimensions and what they mean.
    Modified from skimage.color.guess_spatial_dimensions.

    If the image has two dimensions, it is assumed to contain intensity values
    (i.e. be a greyscale image).
    If the image has three dimensions and the third is length 3, it is assumed
    to be an RGB or similar tri-colour image
    (third dimension indexes colour channel).
    If the image is 3D with the third dimension	length 2, it is assumed to be
    an IA image
    (I = intensity, A = alpha (transparency)).
    If the image is 3D with the third dimension	length 4, it is assumed to be
    an RGBA image.

    Args:
        image: ndarray
            The input image.

    Returns:
        assumption (string): how to treat the image in the future.
            Returns a string telling future scripts how to treat the image for
            filtering. Can be:
            "I" (intensity), "IA" (intensity, alpha),
            "RGB", "RGBA" (rgb, alpha).

    Raises:
        ValueError: If the image array has less than two or more than
        three dimensions.

    """
    if image.ndim == 2:
        return "I"
    if image.ndim == 3 and image.shape[-1] == 1:
        raise ValueError("You seem to have passed an array with "
                         "a third dimension of length 1. Please drop the 3rd "
                         "dimension using np.squeeze and try again.")
    if image.ndim == 3 and image.shape[-1] == 2:
        return "IA"
    if image.ndim == 3 and image.shape[-1] == 3:
        return "RGB"
    if image.ndim == 3 and image.shape[-1] == 4:
        return "RGBA"
    else:
        raise ValueError("Expected 2D or 3D array, got %iD." % image.ndim)

def contrast_image(image, factor=1.0, sd=None,
                   returns="intensity",
                   img_dims=None, verbose=False):
    """Takes an input image, applies a transform to each colour channel,
    then returns either the image in intensity units or in
    zero-mean (contrast) units. The latter can be useful if you intend to
    multiply the image by any filters in the non-fourier domain.

    The transform can either be a multiplicative change (specified by
    factor) or the user can specify the `sd` argument, in which case each
    colour channel will have this standard deviation. If `sd` is specified
    then `factor` is ignored.

    Note: the image will be converted to float, if it wasn't already,
    and a copy will be created (i.e. this function doesn't overwrite
    the original image you pass in).

    Args:
        image (ndarray): The input image.
        factor (float, optional): the contrast scale factor.
            A multiplicative contrast change factor. Values less
            than one will reduce global contrast, values greater
            than one will increase global contrast.
        sd (float, optional): the desired standard deviation.
            Each colour channel will be set to have this sd. Note
            this means that relative differences between colour
            channels in the original image will be moved, meaning
            that the colour gamut will not be the same. If
            `sd` is specified `factor` is ignored.
        returns (string, optional): which image to return.
            If "intensity" (the default), the image is returned
            in intensity units (the original scale) after contrast scaling.
            If returns = "contrast", the array returned has mean zero
            in each colour channel.
        img_dims (string, optional): specify image type.
            If "None", check image dimensions with guess_type. Otherwise,
            specify either "I", "IA", "RGB", "RGBA".
            See guess_type? for more details.
        verbose (bool, optional): If True, print additional information.

    Returns:
        image: ndarray
            the modified image. Either zero mean (if "returns" == "contrast")
            or with the original mean. Returned as floating point array.

    """

    image = img_as_float(np.copy(image))

    if img_dims is None:
        im_type = guess_type(image)
    else:
        im_type = img_dims

    if verbose is True:
        print("contrast_image function assumes image to be " + im_type)
        if sd is None:
            print("Image will change by factor " + str(factor))
        else:
            print("Intensity SD will be set to " + str(sd))

    if im_type is "I":
        channel_means = np.array(image.mean())
        image = image - channel_means

        if sd is None:
            image *= factor
        else:
            image = (image / image.std()) * sd

        if returns is "intensity":
            image = image + channel_means

    elif im_type is "RGB":
        channel_means = np.zeros(3)
        for i in range(0, 3):
            channel_means[i] = image[:, :, i].mean()
            image[:, :, i] = image[:, :, i] - channel_means[i]
            if sd is None:
                image[:, :, i] = image[:, :, i] * factor
            else:
                image[:, :, i] = (image[:, :, i] / image[:, :, i] .std()) * sd
            if returns is "intensity":
                image[:, :, i] = image[:, :, i] + channel_means[i]

    elif im_type is "IA":
        i = 0
        channel_means = image[:, :, i].mean()
        image[:, :, i] = image[:, :, i] - channel_means
        if sd is None:
            image[:, :, i] = image[:, :, i] * factor
        else:
            image[:, :, i] = (image[:, :, i] / image[:, :, i] .std()) * sd

        if returns is "intensity":
            image[:, :, i] = image[:, :, i] + channel_means

    elif im_type is "RGBA":
        channel_means = np.zeros(3)
        for i in range(0, 3):
            channel_means[i] = image[:, :, i].mean()
            image[:, :, i] = image[:, :, i] - channel_means[i]
            if sd is None:
                image[:, :, i] = image[:, :, i] * factor
            else:
                image[:, :, i] = (image[:, :, i] / image[:, :, i] .std()) * sd
            if returns is "intensity":
                image[:, :, i] = image[:, :, i] + channel_means[i]
    else:
        raise ValueError("Not sure what to do with image type " + im_type)

    if returns is "intensity" or returns is "contrast":
        return image
    else:
        raise ValueError("Not sure what to return from " + returns)

def ia_2_rgba(im):
    """ Convert an MxNx2 image (interpreted as an intensity map plus alpha
    level) to an RGBA image (MxNx4). The channels will be rescaled to the
    range 0--1 and converted to float.

    THIS FUNCTION IS QUICK AND DIRTY AND SHOULD ONLY BE USED TO DISPLAY
    IMAGES, NOT SAVE THEM AT THIS STAGE.
    """

    rgba = np.ndarray((im.shape[0], im.shape[1], 4), dtype=np.float)
    im = img_as_float(im.copy())
    rgb = color.gray2rgb(im[..., 0])
    rgba[..., :3] = rgb
    rgba[..., 3] = im[..., 1]

    rgba = exposure.rescale_intensity(rgba, out_range=(0, 1))

    return(rgba)

def save_im(fname, im, bitdepth=8):
    """
    Takes a numpy array, converts it to either uint8 or uint16, and
    saves it to a .png file by converting it to
    an unsigned integer. This is a wrapper for skimage.io.imsave,
    and calls the freeimage library to allow saving with high
    bit depth (8 or 16). Both scikit-image and Freeimage must be
    installed for this to work. On OSX Freeimage can be installed
    using homebrew.

    If the array passed is MxN, the resulting file (.png) will be
    greyscale. If the file is MxNx3 it will be RGB, if MxNx4 it's
    RGBA.

    Warning: old versions of scikit-image (pre 0.11.0) will mess up the
    order of the colour planes and mirror flip images if bitdepth is 16.

    Args:
        fname (string):
            the filename to save the image to.
        im (ndarray, float):
            a numpy array (either 2D or 3D) to save.
        bitdepth (int):
            either 8 or 16.
    """

    # dims = guess_type(im)
    # im = img_as_float(im)
    # check scale:
    # im = exposure.rescale_intensity(im, out_range='float')

    if bitdepth is 8:
        # convert to uint8:
        im = img_as_ubyte(im)

    elif bitdepth is 16:
        # convert to 16 bit
        im = img_as_uint(im)

        # # to fix bug in current release of scikit-image (issue 1101; closed)
        # if dims == "RGB" or dims == "RGBA":
        #     im = np.fliplr(np.flipud(im))
        io.use_plugin('freeimage')

    io.imsave(fname, im)

def put_rect_in_rect(rect_a, rect_b, midpoints=None):
    """A function to place rect_a inside rect_b.

    This function will place np.ndarray `a` into np.ndarray
    `b`, centred on the point mid_x, mid_y. Currently only for 2D arrays.

    Args:
        rect_a (np.ndarray):
            the source rectangle.
        rect_b (np.ndarray):
            the destination rectangle.
        midpoints (tuple or int, optional):
            where to place the centre of rect_a in rect_b. Defaults to the
            middle of rect_b. If a scalar is given, the mid_x and mid_y points
            will be the same. If a tuple is given, the first element is the
            horizontal middle, the second element is the vertical middle (i.e.
            mid_x and mid_y).
    Returns:
        np.ndarray containing the new rectangle.

    """

    new_rect = rect_b.copy()

    if midpoints is None:
        mid_x = rect_b.shape[1] / 2
        mid_y = rect_b.shape[0] / 2
    else:
        mid_x, mid_y = pu.image.parse_size(midpoints)

    rect_a_rad_x = rect_a.shape[1] / 2
    rect_a_rad_y = rect_a.shape[0] / 2

    x_start = mid_x - rect_a_rad_x
    y_start = mid_y - rect_a_rad_y
    x_end = x_start + rect_a.shape[1]
    y_end = y_start + rect_a.shape[0]

    if x_start < 0 or y_start < 0:
        raise ValueError("Rect_a falls outside rect_b! " +
                         "x_start is " + str(x_start) +
                         " , y_start is " + str(y_start))
    if x_end > rect_b.shape[1] or y_end > rect_b.shape[0]:
        raise ValueError("Rect_a falls outside rect_b!" +
                         "x_end is " + str(x_end) +
                         " , y_end is " + str(y_end))

    new_rect[int(y_start):int(y_end), int(x_start):int(x_end)] = rect_a

    return(new_rect)

def cutout_patch(im, size, midpoints=None):
    """A function to cut a patch out of the np.ndarray `im`. Currently
    only for 2D arrays.

    Returns a rectangle specified by `size`, centred on the points
    `mid_x` and `mid_y` in the image `im`.

    Args:
        im (np.ndarray):
            the larger rectangle from which to remove a patch.
        size (int or tuple of ints):
            the size of the rectangle in w, h. If a scalar is provided cutout
            is square.
        midpoints (tuple or int, optional):
            where to place the centre of rect_a in rect_b. Defaults to the
            middle of rect_b. If a scalar is given, the mid_x and mid_y points
            will be the same. If a tuple is given, the first element is the
            horizontal middle, the second element is the vertical middle (i.e.
            mid_x and mid_y).

    Returns:
        np.ndarray containing the cutout.

    """

    im = im.copy()

    if midpoints is None:
        mid_x = im.shape[1] / 2
        mid_y = im.shape[0] / 2
    else:
        mid_x, mid_y = pu.image.parse_size(midpoints)

    w, h = pu.image.parse_size(size)

    x_start = mid_x - (w / 2)
    y_start = mid_y - (h / 2)
    x_end = x_start + w
    y_end = y_start + h

    if x_start < 0 or y_start < 0:
        raise ValueError("Rect_a falls outside rect_b! " +
                         "x_start is " + str(x_start) +
                         " , y_start is " + str(y_start))
    if x_end > im.shape[1] or y_end > im.shape[0]:
        raise ValueError("Rect_a falls outside rect_b!" +
                         "x_end is " + str(x_end) +
                         " , y_end is " + str(y_end))

    res = im[int(y_start):int(y_end), int(x_start):int(x_end)]
    return(res)

def linear_rescale(im, maxmin=(-1, 1)):
    """ Linearly rescale an image between the values
    given by the tuple `maxmin`.

    Note this is different to skimage's rescale intensity function,
    which respects the contrast of the values. In contrast, this function
    will stretch the range to maxmin[0], maxmin[1].

    """

    im_std = (im - im.min()) / (im.max() - im.min())
    im_scaled = im_std * (maxmin[1] - maxmin[0]) + maxmin[0]
    return(im_scaled)

def alpha_blend(fg, bg):
    """ Do alpha blending putting foreground `fg` in front of background
    `bg`.

    Input images should be floats scaled in the 0--1 range.

    Input images are assumed to be images whose third dimension is
    4 (i.e. RGBA).

    """

    fg_rgb = fg[..., :3]
    fg_alpha = fg[..., 3]
    bg_rgb = bg[..., :3]
    bg_alpha = bg[..., 3]

    out_alpha = fg_alpha + bg_alpha * (1. - fg_alpha)

    # # check for any zeros:
    # out_alpha[out_alpha == 0] = 1e-12

    out_rgb = (fg_rgb * fg_alpha[..., None] +
               bg_rgb * (1. - fg_alpha[..., None])) / out_alpha[..., None]

    out = np.zeros_like(bg)
    out[..., :3] = out_rgb
    out[..., 3] = out_alpha
    # out = exposure.rescale_intensity(out, out_range=(0, 1))
    return(out)
<commit_msg>another import division.<commit_after>import numpy as np
from skimage import img_as_float, io, exposure, img_as_uint, color, img_as_ubyte
import matplotlib.pyplot as plt
import psyutils as pu
from __future__ import print_function, division

def guess_type(image):
    """Make an educated guess about an image's dimensions and what they mean.
    Modified from skimage.color.guess_spatial_dimensions.

    If the image has two dimensions, it is assumed to contain intensity values
    (i.e. be a greyscale image).
    If the image has three dimensions and the third is length 3, it is assumed
    to be an RGB or similar tri-colour image
    (third dimension indexes colour channel).
    If the image is 3D with the third dimension	length 2, it is assumed to be
    an IA image
    (I = intensity, A = alpha (transparency)).
    If the image is 3D with the third dimension	length 4, it is assumed to be
    an RGBA image.

    Args:
        image: ndarray
            The input image.

    Returns:
        assumption (string): how to treat the image in the future.
            Returns a string telling future scripts how to treat the image for
            filtering. Can be:
            "I" (intensity), "IA" (intensity, alpha),
            "RGB", "RGBA" (rgb, alpha).

    Raises:
        ValueError: If the image array has less than two or more than
        three dimensions.

    """
    if image.ndim == 2:
        return "I"
    if image.ndim == 3 and image.shape[-1] == 1:
        raise ValueError("You seem to have passed an array with "
                         "a third dimension of length 1. Please drop the 3rd "
                         "dimension using np.squeeze and try again.")
    if image.ndim == 3 and image.shape[-1] == 2:
        return "IA"
    if image.ndim == 3 and image.shape[-1] == 3:
        return "RGB"
    if image.ndim == 3 and image.shape[-1] == 4:
        return "RGBA"
    else:
        raise ValueError("Expected 2D or 3D array, got %iD." % image.ndim)

def contrast_image(image, factor=1.0, sd=None,
                   returns="intensity",
                   img_dims=None, verbose=False):
    """Takes an input image, applies a transform to each colour channel,
    then returns either the image in intensity units or in
    zero-mean (contrast) units. The latter can be useful if you intend to
    multiply the image by any filters in the non-fourier domain.

    The transform can either be a multiplicative change (specified by
    factor) or the user can specify the `sd` argument, in which case each
    colour channel will have this standard deviation. If `sd` is specified
    then `factor` is ignored.

    Note: the image will be converted to float, if it wasn't already,
    and a copy will be created (i.e. this function doesn't overwrite
    the original image you pass in).

    Args:
        image (ndarray): The input image.
        factor (float, optional): the contrast scale factor.
            A multiplicative contrast change factor. Values less
            than one will reduce global contrast, values greater
            than one will increase global contrast.
        sd (float, optional): the desired standard deviation.
            Each colour channel will be set to have this sd. Note
            this means that relative differences between colour
            channels in the original image will be moved, meaning
            that the colour gamut will not be the same. If
            `sd` is specified `factor` is ignored.
        returns (string, optional): which image to return.
            If "intensity" (the default), the image is returned
            in intensity units (the original scale) after contrast scaling.
            If returns = "contrast", the array returned has mean zero
            in each colour channel.
        img_dims (string, optional): specify image type.
            If "None", check image dimensions with guess_type. Otherwise,
            specify either "I", "IA", "RGB", "RGBA".
            See guess_type? for more details.
        verbose (bool, optional): If True, print additional information.

    Returns:
        image: ndarray
            the modified image. Either zero mean (if "returns" == "contrast")
            or with the original mean. Returned as floating point array.

    """

    image = img_as_float(np.copy(image))

    if img_dims is None:
        im_type = guess_type(image)
    else:
        im_type = img_dims

    if verbose is True:
        print("contrast_image function assumes image to be " + im_type)
        if sd is None:
            print("Image will change by factor " + str(factor))
        else:
            print("Intensity SD will be set to " + str(sd))

    if im_type is "I":
        channel_means = np.array(image.mean())
        image = image - channel_means

        if sd is None:
            image *= factor
        else:
            image = (image / image.std()) * sd

        if returns is "intensity":
            image = image + channel_means

    elif im_type is "RGB":
        channel_means = np.zeros(3)
        for i in range(0, 3):
            channel_means[i] = image[:, :, i].mean()
            image[:, :, i] = image[:, :, i] - channel_means[i]
            if sd is None:
                image[:, :, i] = image[:, :, i] * factor
            else:
                image[:, :, i] = (image[:, :, i] / image[:, :, i] .std()) * sd
            if returns is "intensity":
                image[:, :, i] = image[:, :, i] + channel_means[i]

    elif im_type is "IA":
        i = 0
        channel_means = image[:, :, i].mean()
        image[:, :, i] = image[:, :, i] - channel_means
        if sd is None:
            image[:, :, i] = image[:, :, i] * factor
        else:
            image[:, :, i] = (image[:, :, i] / image[:, :, i] .std()) * sd

        if returns is "intensity":
            image[:, :, i] = image[:, :, i] + channel_means

    elif im_type is "RGBA":
        channel_means = np.zeros(3)
        for i in range(0, 3):
            channel_means[i] = image[:, :, i].mean()
            image[:, :, i] = image[:, :, i] - channel_means[i]
            if sd is None:
                image[:, :, i] = image[:, :, i] * factor
            else:
                image[:, :, i] = (image[:, :, i] / image[:, :, i] .std()) * sd
            if returns is "intensity":
                image[:, :, i] = image[:, :, i] + channel_means[i]
    else:
        raise ValueError("Not sure what to do with image type " + im_type)

    if returns is "intensity" or returns is "contrast":
        return image
    else:
        raise ValueError("Not sure what to return from " + returns)

def ia_2_rgba(im):
    """ Convert an MxNx2 image (interpreted as an intensity map plus alpha
    level) to an RGBA image (MxNx4). The channels will be rescaled to the
    range 0--1 and converted to float.

    THIS FUNCTION IS QUICK AND DIRTY AND SHOULD ONLY BE USED TO DISPLAY
    IMAGES, NOT SAVE THEM AT THIS STAGE.
    """

    rgba = np.ndarray((im.shape[0], im.shape[1], 4), dtype=np.float)
    im = img_as_float(im.copy())
    rgb = color.gray2rgb(im[..., 0])
    rgba[..., :3] = rgb
    rgba[..., 3] = im[..., 1]

    rgba = exposure.rescale_intensity(rgba, out_range=(0, 1))

    return(rgba)

def save_im(fname, im, bitdepth=8):
    """
    Takes a numpy array, converts it to either uint8 or uint16, and
    saves it to a .png file by converting it to
    an unsigned integer. This is a wrapper for skimage.io.imsave,
    and calls the freeimage library to allow saving with high
    bit depth (8 or 16). Both scikit-image and Freeimage must be
    installed for this to work. On OSX Freeimage can be installed
    using homebrew.

    If the array passed is MxN, the resulting file (.png) will be
    greyscale. If the file is MxNx3 it will be RGB, if MxNx4 it's
    RGBA.

    Warning: old versions of scikit-image (pre 0.11.0) will mess up the
    order of the colour planes and mirror flip images if bitdepth is 16.

    Args:
        fname (string):
            the filename to save the image to.
        im (ndarray, float):
            a numpy array (either 2D or 3D) to save.
        bitdepth (int):
            either 8 or 16.
    """

    # dims = guess_type(im)
    # im = img_as_float(im)
    # check scale:
    # im = exposure.rescale_intensity(im, out_range='float')

    if bitdepth is 8:
        # convert to uint8:
        im = img_as_ubyte(im)

    elif bitdepth is 16:
        # convert to 16 bit
        im = img_as_uint(im)

        # # to fix bug in current release of scikit-image (issue 1101; closed)
        # if dims == "RGB" or dims == "RGBA":
        #     im = np.fliplr(np.flipud(im))
        io.use_plugin('freeimage')

    io.imsave(fname, im)

def put_rect_in_rect(rect_a, rect_b, midpoints=None):
    """A function to place rect_a inside rect_b.

    This function will place np.ndarray `a` into np.ndarray
    `b`, centred on the point mid_x, mid_y. Currently only for 2D arrays.

    Args:
        rect_a (np.ndarray):
            the source rectangle.
        rect_b (np.ndarray):
            the destination rectangle.
        midpoints (tuple or int, optional):
            where to place the centre of rect_a in rect_b. Defaults to the
            middle of rect_b. If a scalar is given, the mid_x and mid_y points
            will be the same. If a tuple is given, the first element is the
            horizontal middle, the second element is the vertical middle (i.e.
            mid_x and mid_y).
    Returns:
        np.ndarray containing the new rectangle.

    """

    new_rect = rect_b.copy()

    if midpoints is None:
        mid_x = rect_b.shape[1] / 2
        mid_y = rect_b.shape[0] / 2
    else:
        mid_x, mid_y = pu.image.parse_size(midpoints)

    rect_a_rad_x = rect_a.shape[1] / 2
    rect_a_rad_y = rect_a.shape[0] / 2

    x_start = mid_x - rect_a_rad_x
    y_start = mid_y - rect_a_rad_y
    x_end = x_start + rect_a.shape[1]
    y_end = y_start + rect_a.shape[0]

    if x_start < 0 or y_start < 0:
        raise ValueError("Rect_a falls outside rect_b! " +
                         "x_start is " + str(x_start) +
                         " , y_start is " + str(y_start))
    if x_end > rect_b.shape[1] or y_end > rect_b.shape[0]:
        raise ValueError("Rect_a falls outside rect_b!" +
                         "x_end is " + str(x_end) +
                         " , y_end is " + str(y_end))

    new_rect[int(y_start):int(y_end), int(x_start):int(x_end)] = rect_a

    return(new_rect)

def cutout_patch(im, size, midpoints=None):
    """A function to cut a patch out of the np.ndarray `im`. Currently
    only for 2D arrays.

    Returns a rectangle specified by `size`, centred on the points
    `mid_x` and `mid_y` in the image `im`.

    Args:
        im (np.ndarray):
            the larger rectangle from which to remove a patch.
        size (int or tuple of ints):
            the size of the rectangle in w, h. If a scalar is provided cutout
            is square.
        midpoints (tuple or int, optional):
            where to place the centre of rect_a in rect_b. Defaults to the
            middle of rect_b. If a scalar is given, the mid_x and mid_y points
            will be the same. If a tuple is given, the first element is the
            horizontal middle, the second element is the vertical middle (i.e.
            mid_x and mid_y).

    Returns:
        np.ndarray containing the cutout.

    """

    im = im.copy()

    if midpoints is None:
        mid_x = im.shape[1] / 2
        mid_y = im.shape[0] / 2
    else:
        mid_x, mid_y = pu.image.parse_size(midpoints)

    w, h = pu.image.parse_size(size)

    x_start = mid_x - (w / 2)
    y_start = mid_y - (h / 2)
    x_end = x_start + w
    y_end = y_start + h

    if x_start < 0 or y_start < 0:
        raise ValueError("Rect_a falls outside rect_b! " +
                         "x_start is " + str(x_start) +
                         " , y_start is " + str(y_start))
    if x_end > im.shape[1] or y_end > im.shape[0]:
        raise ValueError("Rect_a falls outside rect_b!" +
                         "x_end is " + str(x_end) +
                         " , y_end is " + str(y_end))

    res = im[int(y_start):int(y_end), int(x_start):int(x_end)]
    return(res)

def linear_rescale(im, maxmin=(-1, 1)):
    """ Linearly rescale an image between the values
    given by the tuple `maxmin`.

    Note this is different to skimage's rescale intensity function,
    which respects the contrast of the values. In contrast, this function
    will stretch the range to maxmin[0], maxmin[1].

    """

    im_std = (im - im.min()) / (im.max() - im.min())
    im_scaled = im_std * (maxmin[1] - maxmin[0]) + maxmin[0]
    return(im_scaled)

def alpha_blend(fg, bg):
    """ Do alpha blending putting foreground `fg` in front of background
    `bg`.

    Input images should be floats scaled in the 0--1 range.

    Input images are assumed to be images whose third dimension is
    4 (i.e. RGBA).

    """

    fg_rgb = fg[..., :3]
    fg_alpha = fg[..., 3]
    bg_rgb = bg[..., :3]
    bg_alpha = bg[..., 3]

    out_alpha = fg_alpha + bg_alpha * (1. - fg_alpha)

    # # check for any zeros:
    # out_alpha[out_alpha == 0] = 1e-12

    out_rgb = (fg_rgb * fg_alpha[..., None] +
               bg_rgb * (1. - fg_alpha[..., None])) / out_alpha[..., None]

    out = np.zeros_like(bg)
    out[..., :3] = out_rgb
    out[..., 3] = out_alpha
    # out = exposure.rescale_intensity(out, out_range=(0, 1))
    return(out)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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 datetime
import mock

import st2actions.utils.param_utils as param_utils
from st2common.exceptions import actionrunner
from st2common.models.system.common import ResourceReference
from st2common.models.db.action import (ActionDB, ActionExecutionDB)
from st2common.models.api.action import RunnerTypeAPI
from st2common.transport.publishers import PoolPublisher
from unittest2 import TestCase

@mock.patch.object(PoolPublisher, 'publish', mock.MagicMock())
class ParamsUtilsTest(TestCase):
    action_db = None
    runnertype_db = None

    @classmethod
    def setUpClass(cls):
        super(ParamsUtilsTest, cls).setUpClass()
        ParamsUtilsTest._setup_test_models()

    def test_get_resolved_params(self):
        params = {
            'actionstr': 'foo',
            'some_key_that_aint_exist_in_action_or_runner': 'bar',
            'runnerint': 555,
            'runnerimmutable': 'failed_override',
            'actionimmutable': 'failed_override'
        }
        actionexec_db = self._get_action_exec_db_model(params)

        runner_params, action_params = param_utils.get_resolved_params(
            ParamsUtilsTest.runnertype_db.runner_parameters,
            ParamsUtilsTest.action_db.parameters,
            actionexec_db.parameters)

        # Asserts for runner params.
        # Assert that default values for runner params are resolved.
        self.assertEqual(runner_params.get('runnerstr'), 'defaultfoo')
        # Assert that a runner param from action exec is picked up.
        self.assertEqual(runner_params.get('runnerint'), 555)
        # Assert that a runner param can be overriden by action param default.
        self.assertEqual(runner_params.get('runnerdummy'), 'actiondummy')
        # Asser that runner param made immutable in action can use default value in runner.
        self.assertEqual(runner_params.get('runnerfoo'), 'FOO')
        # Assert that an immutable param cannot be overriden by action param or execution param.
        self.assertEqual(runner_params.get('runnerimmutable'), 'runnerimmutable')

        # Asserts for action params.
        self.assertEqual(action_params.get('actionstr'), 'foo')
        # Assert that a param that is provided in action exec that isn't in action or runner params
        # isn't in resolved params.
        self.assertEqual(action_params.get('some_key_that_aint_exist_in_action_or_runner'), None)
        # Assert that an immutable param cannot be overriden by execution param.
        self.assertEqual(action_params.get('actionimmutable'), 'actionimmutable')
        # Assert that none of runner params are present in action_params.
        for k in action_params:
            self.assertTrue(k not in runner_params, 'Param ' + k + ' is a runner param.')

    def test_get_finalized_params(self):
        params = {
            'actionstr': 'foo',
            'some_key_that_aint_exist_in_action_or_runner': 'bar',
            'runnerint': 555,
            'runnerimmutable': 'failed_override',
            'actionimmutable': 'failed_override'
        }
        actionexec_db = self._get_action_exec_db_model(params)

        runner_params, action_params = param_utils.get_finalized_params(
            ParamsUtilsTest.runnertype_db.runner_parameters,
            ParamsUtilsTest.action_db.parameters,
            actionexec_db.parameters)

        # Asserts for runner params.
        # Assert that default values for runner params are resolved.
        self.assertEqual(runner_params.get('runnerstr'), 'defaultfoo')
        # Assert that a runner param from action exec is picked up.
        self.assertEqual(runner_params.get('runnerint'), 555)
        # Assert that a runner param can be overriden by action param default.
        self.assertEqual(runner_params.get('runnerdummy'), 'actiondummy')
        # Assert that an immutable param cannot be overriden by action param or execution param.
        self.assertEqual(runner_params.get('runnerimmutable'), 'runnerimmutable')

        # Asserts for action params.
        self.assertEqual(action_params.get('actionstr'), 'foo')
        # Assert that a param that is provided in action exec that isn't in action or runner params
        # isn't in resolved params.
        self.assertEqual(action_params.get('some_key_that_aint_exist_in_action_or_runner'), None)
        # Assert that an immutable param cannot be overriden by execution param.
        self.assertEqual(action_params.get('actionimmutable'), 'actionimmutable')
        # Assert that none of runner params are present in action_params.
        for k in action_params:
            self.assertTrue(k not in runner_params, 'Param ' + k + ' is a runner param.')

    def test_get_resolved_params_action_immutable(self):
        params = {
            'actionstr': 'foo',
            'some_key_that_aint_exist_in_action_or_runner': 'bar',
            'runnerint': 555,
            'actionimmutable': 'failed_override'
        }
        actionexec_db = self._get_action_exec_db_model(params)

        runner_params, action_params = param_utils.get_resolved_params(
            ParamsUtilsTest.runnertype_db.runner_parameters,
            ParamsUtilsTest.action_db.parameters,
            actionexec_db.parameters)

        # Asserts for runner params.
        # Assert that default values for runner params are resolved.
        self.assertEqual(runner_params.get('runnerstr'), 'defaultfoo')
        # Assert that a runner param from action exec is picked up.
        self.assertEqual(runner_params.get('runnerint'), 555)
        # Assert that a runner param can be overriden by action param default.
        self.assertEqual(runner_params.get('runnerdummy'), 'actiondummy')

        # Asserts for action params.
        self.assertEqual(action_params.get('actionstr'), 'foo')
        # Assert that a param that is provided in action exec that isn't in action or runner params
        # isn't in resolved params.
        self.assertEqual(action_params.get('some_key_that_aint_exist_in_action_or_runner'), None)

    def test_get_rendered_params_empty(self):
        runner_params = {}
        action_params = {}
        runner_param_info = {}
        action_param_info = {}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, runner_params)
        self.assertEqual(r_action_params, action_params)

    def test_get_rendered_params_none(self):
        runner_params = {'r1': None}
        action_params = {'a1': None}
        runner_param_info = {'r1': {}}
        action_param_info = {'a1': {}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, runner_params)
        self.assertEqual(r_action_params, action_params)

    def test_get_rendered_params_no_cast(self):
        runner_params = {'r1': '{{r2}}', 'r2': 1}
        action_params = {'a1': True, 'a2': '{{r1}} {{a1}}'}
        runner_param_info = {'r1': {}, 'r2': {}}
        action_param_info = {'a1': {}, 'a2': {}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': u'1', 'r2': 1})
        self.assertEqual(r_action_params, {'a1': True, 'a2': u'1 True'})

    def test_get_rendered_params_with_cast(self):
        # Note : In this test runner_params.r1 has a string value. However per runner_param_info the
        # type is an integer. The expected type is considered and cast is performed accordingly.
        runner_params = {'r1': '{{r2}}', 'r2': 1}
        action_params = {'a1': True, 'a2': '{{a1}}'}
        runner_param_info = {'r1': {'type': 'integer'}, 'r2': {'type': 'integer'}}
        action_param_info = {'a1': {'type': 'boolean'}, 'a2': {'type': 'boolean'}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': 1, 'r2': 1})
        self.assertEqual(r_action_params, {'a1': True, 'a2': True})

    def test_unicode_value_casting(self):
        rendered = {'a1': 'unicode1 ٩(̾●̮̮̃̾•̃̾)۶ unicode2'}
        parameter_schemas = {'a1': {'type': 'string'}}

        result = param_utils._cast_params(rendered=rendered,
                                          parameter_schemas=parameter_schemas)
        expected = {
            'a1': (u'unicode1 \xd9\xa9(\xcc\xbe\xe2\x97\x8f\xcc\xae\xcc\xae\xcc'
                   u'\x83\xcc\xbe\xe2\x80\xa2\xcc\x83\xcc\xbe)\xdb\xb6 unicode2')
        }
        self.assertEqual(result, expected)

    def test_get_rendered_params_with_casting_unicode_values(self):
        runner_params = {}
        action_params = {'a1': 'unicode1 ٩(̾●̮̮̃̾•̃̾)۶ unicode2'}

        runner_param_info = {}
        action_param_info = {'a1': {'type': 'string'}}

        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)

        expected_action_params = {
            'a1': (u'unicode1 \xd9\xa9(\xcc\xbe\xe2\x97\x8f\xcc\xae\xcc\xae\xcc'
                   u'\x83\xcc\xbe\xe2\x80\xa2\xcc\x83\xcc\xbe)\xdb\xb6 unicode2')
        }
        self.assertEqual(r_runner_params, {})
        self.assertEqual(r_action_params, expected_action_params)

    def test_get_rendered_params_with_dict(self):
        # Note : In this test runner_params.r1 has a string value. However per runner_param_info the
        # type is an integer. The expected type is considered and cast is performed accordingly.
        runner_params = {'r1': '{{r2}}', 'r2': {'r2.1': 1}}
        action_params = {'a1': True, 'a2': '{{a1}}'}
        runner_param_info = {'r1': {'type': 'object'}, 'r2': {'type': 'object'}}
        action_param_info = {'a1': {'type': 'boolean'}, 'a2': {'type': 'boolean'}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': {'r2.1': 1}, 'r2': {'r2.1': 1}})
        self.assertEqual(r_action_params, {'a1': True, 'a2': True})

    def test_get_rendered_params_with_list(self):
        # Note : In this test runner_params.r1 has a string value. However per runner_param_info the
        # type is an integer. The expected type is considered and cast is performed accordingly.
        runner_params = {'r1': '{{r2}}', 'r2': ['1', '2']}
        action_params = {'a1': True, 'a2': '{{a1}}'}
        runner_param_info = {'r1': {'type': 'array'}, 'r2': {'type': 'array'}}
        action_param_info = {'a1': {'type': 'boolean'}, 'a2': {'type': 'boolean'}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': ['1', '2'], 'r2': ['1', '2']})
        self.assertEqual(r_action_params, {'a1': True, 'a2': True})

    def test_get_rendered_params_with_cyclic_dependency(self):
        runner_params = {'r1': '{{r2}}', 'r2': '{{r1}}'}
        test_pass = True
        try:
            param_utils.get_rendered_params(runner_params, {}, {}, {})
            test_pass = False
        except actionrunner.ActionRunnerException as e:
            test_pass = e.message.find('Cyclic') == 0
        self.assertTrue(test_pass)

    def test_get_rendered_params_with_missing_dependency(self):
        runner_params = {'r1': '{{r3}}', 'r2': '{{r3}}'}
        test_pass = True
        try:
            param_utils.get_rendered_params(runner_params, {}, {}, {})
            test_pass = False
        except actionrunner.ActionRunnerException as e:
            test_pass = e.message.find('Dependecy') == 0
        self.assertTrue(test_pass)

    def _get_action_exec_db_model(self, params):
        actionexec_db = ActionExecutionDB()
        actionexec_db.status = 'initializing'
        actionexec_db.start_timestamp = datetime.datetime.utcnow()
        actionexec_db.action = ResourceReference(name=ParamsUtilsTest.action_db.name,
                                                 pack=ParamsUtilsTest.action_db.pack).ref
        actionexec_db.parameters = params

        return actionexec_db

    @classmethod
    def _setup_test_models(cls):
        ParamsUtilsTest._setup_runner_models()
        ParamsUtilsTest._setup_action_models()

    @classmethod
    def _setup_runner_models(cls):
        test_runner = {
            'name': 'test-runner',
            'description': 'A test runner.',
            'enabled': True,
            'runner_parameters': {
                'runnerstr': {
                    'description': 'Foo str param.',
                    'type': 'string',
                    'default': 'defaultfoo'
                },
                'runnerint': {
                    'description': 'Foo int param.',
                    'type': 'number'
                },
                'runnerfoo': {
                    'description': 'Some foo param.',
                    'default': 'FOO'
                },
                'runnerdummy': {
                    'description': 'Dummy param.',
                    'type': 'string',
                    'default': 'runnerdummy'
                },
                'runnerimmutable': {
                    'description': 'Immutable param.',
                    'type': 'string',
                    'default': 'runnerimmutable',
                    'immutable': True
                }
            },
            'runner_module': 'tests.test_runner'
        }
        runnertype_api = RunnerTypeAPI(**test_runner)
        ParamsUtilsTest.runnertype_db = RunnerTypeAPI.to_model(runnertype_api)

    @classmethod
    def _setup_action_models(cls):
        action_db = ActionDB()
        action_db.name = 'action-1'
        action_db.description = 'awesomeness'
        action_db.enabled = True
        action_db.pack = 'wolfpack'
        action_db.entry_point = ''
        action_db.runner_type = {'name': 'test-runner'}
        action_db.parameters = {
            'actionstr': {'type': 'string', 'required': True},
            'actionint': {'type': 'number', 'default': 10},
            'runnerdummy': {'type': 'string', 'default': 'actiondummy', 'immutable': True},
            'runnerfoo': {'type': 'string', 'immutable': True},
            'runnerimmutable': {'type': 'string', 'default': 'failed_override'},
            'actionimmutable': {'type': 'string', 'default': 'actionimmutable', 'immutable': True}
        }
        ParamsUtilsTest.action_db = action_db
<commit_msg>Use fixtures in test_param_utils<commit_after># -*- coding: utf-8 -*-
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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 datetime
import mock

import st2actions.utils.param_utils as param_utils
from st2common.exceptions import actionrunner
from st2common.models.system.common import ResourceReference
from st2common.models.db.action import (ActionDB, ActionExecutionDB)
from st2common.models.api.action import RunnerTypeAPI
from st2common.transport.publishers import PoolPublisher
from st2tests.fixturesloader import FixturesLoader
from unittest2 import TestCase

FIXTURES_PACK = 'generic'

TEST_MODELS = {
    'actions': ['action1.json'],
    'runners': ['testrunner1.json']
}

FIXTURES = FixturesLoader().load_models(fixtures_pack=FIXTURES_PACK,
                                        fixtures_dict=TEST_MODELS)

@mock.patch.object(PoolPublisher, 'publish', mock.MagicMock())
class ParamsUtilsTest(TestCase):
    action_db = FIXTURES['actions']['action1.json']
    runnertype_db = FIXTURES['runners']['testrunner1.json']

    def test_get_resolved_params(self):
        params = {
            'actionstr': 'foo',
            'some_key_that_aint_exist_in_action_or_runner': 'bar',
            'runnerint': 555,
            'runnerimmutable': 'failed_override',
            'actionimmutable': 'failed_override'
        }
        actionexec_db = self._get_action_exec_db_model(params)

        runner_params, action_params = param_utils.get_resolved_params(
            ParamsUtilsTest.runnertype_db.runner_parameters,
            ParamsUtilsTest.action_db.parameters,
            actionexec_db.parameters)

        # Asserts for runner params.
        # Assert that default values for runner params are resolved.
        self.assertEqual(runner_params.get('runnerstr'), 'defaultfoo')
        # Assert that a runner param from action exec is picked up.
        self.assertEqual(runner_params.get('runnerint'), 555)
        # Assert that a runner param can be overriden by action param default.
        self.assertEqual(runner_params.get('runnerdummy'), 'actiondummy')
        # Asser that runner param made immutable in action can use default value in runner.
        self.assertEqual(runner_params.get('runnerfoo'), 'FOO')
        # Assert that an immutable param cannot be overriden by action param or execution param.
        self.assertEqual(runner_params.get('runnerimmutable'), 'runnerimmutable')

        # Asserts for action params.
        self.assertEqual(action_params.get('actionstr'), 'foo')
        # Assert that a param that is provided in action exec that isn't in action or runner params
        # isn't in resolved params.
        self.assertEqual(action_params.get('some_key_that_aint_exist_in_action_or_runner'), None)
        # Assert that an immutable param cannot be overriden by execution param.
        self.assertEqual(action_params.get('actionimmutable'), 'actionimmutable')
        # Assert that none of runner params are present in action_params.
        for k in action_params:
            self.assertTrue(k not in runner_params, 'Param ' + k + ' is a runner param.')

    def test_get_finalized_params(self):
        params = {
            'actionstr': 'foo',
            'some_key_that_aint_exist_in_action_or_runner': 'bar',
            'runnerint': 555,
            'runnerimmutable': 'failed_override',
            'actionimmutable': 'failed_override'
        }
        actionexec_db = self._get_action_exec_db_model(params)

        runner_params, action_params = param_utils.get_finalized_params(
            ParamsUtilsTest.runnertype_db.runner_parameters,
            ParamsUtilsTest.action_db.parameters,
            actionexec_db.parameters)

        # Asserts for runner params.
        # Assert that default values for runner params are resolved.
        self.assertEqual(runner_params.get('runnerstr'), 'defaultfoo')
        # Assert that a runner param from action exec is picked up.
        self.assertEqual(runner_params.get('runnerint'), 555)
        # Assert that a runner param can be overriden by action param default.
        self.assertEqual(runner_params.get('runnerdummy'), 'actiondummy')
        # Assert that an immutable param cannot be overriden by action param or execution param.
        self.assertEqual(runner_params.get('runnerimmutable'), 'runnerimmutable')

        # Asserts for action params.
        self.assertEqual(action_params.get('actionstr'), 'foo')
        # Assert that a param that is provided in action exec that isn't in action or runner params
        # isn't in resolved params.
        self.assertEqual(action_params.get('some_key_that_aint_exist_in_action_or_runner'), None)
        # Assert that an immutable param cannot be overriden by execution param.
        self.assertEqual(action_params.get('actionimmutable'), 'actionimmutable')
        # Assert that none of runner params are present in action_params.
        for k in action_params:
            self.assertTrue(k not in runner_params, 'Param ' + k + ' is a runner param.')

    def test_get_resolved_params_action_immutable(self):
        params = {
            'actionstr': 'foo',
            'some_key_that_aint_exist_in_action_or_runner': 'bar',
            'runnerint': 555,
            'actionimmutable': 'failed_override'
        }
        actionexec_db = self._get_action_exec_db_model(params)

        runner_params, action_params = param_utils.get_resolved_params(
            ParamsUtilsTest.runnertype_db.runner_parameters,
            ParamsUtilsTest.action_db.parameters,
            actionexec_db.parameters)

        # Asserts for runner params.
        # Assert that default values for runner params are resolved.
        self.assertEqual(runner_params.get('runnerstr'), 'defaultfoo')
        # Assert that a runner param from action exec is picked up.
        self.assertEqual(runner_params.get('runnerint'), 555)
        # Assert that a runner param can be overriden by action param default.
        self.assertEqual(runner_params.get('runnerdummy'), 'actiondummy')

        # Asserts for action params.
        self.assertEqual(action_params.get('actionstr'), 'foo')
        # Assert that a param that is provided in action exec that isn't in action or runner params
        # isn't in resolved params.
        self.assertEqual(action_params.get('some_key_that_aint_exist_in_action_or_runner'), None)

    def test_get_rendered_params_empty(self):
        runner_params = {}
        action_params = {}
        runner_param_info = {}
        action_param_info = {}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, runner_params)
        self.assertEqual(r_action_params, action_params)

    def test_get_rendered_params_none(self):
        runner_params = {'r1': None}
        action_params = {'a1': None}
        runner_param_info = {'r1': {}}
        action_param_info = {'a1': {}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, runner_params)
        self.assertEqual(r_action_params, action_params)

    def test_get_rendered_params_no_cast(self):
        runner_params = {'r1': '{{r2}}', 'r2': 1}
        action_params = {'a1': True, 'a2': '{{r1}} {{a1}}'}
        runner_param_info = {'r1': {}, 'r2': {}}
        action_param_info = {'a1': {}, 'a2': {}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': u'1', 'r2': 1})
        self.assertEqual(r_action_params, {'a1': True, 'a2': u'1 True'})

    def test_get_rendered_params_with_cast(self):
        # Note : In this test runner_params.r1 has a string value. However per runner_param_info the
        # type is an integer. The expected type is considered and cast is performed accordingly.
        runner_params = {'r1': '{{r2}}', 'r2': 1}
        action_params = {'a1': True, 'a2': '{{a1}}'}
        runner_param_info = {'r1': {'type': 'integer'}, 'r2': {'type': 'integer'}}
        action_param_info = {'a1': {'type': 'boolean'}, 'a2': {'type': 'boolean'}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': 1, 'r2': 1})
        self.assertEqual(r_action_params, {'a1': True, 'a2': True})

    def test_unicode_value_casting(self):
        rendered = {'a1': 'unicode1 ٩(̾●̮̮̃̾•̃̾)۶ unicode2'}
        parameter_schemas = {'a1': {'type': 'string'}}

        result = param_utils._cast_params(rendered=rendered,
                                          parameter_schemas=parameter_schemas)
        expected = {
            'a1': (u'unicode1 \xd9\xa9(\xcc\xbe\xe2\x97\x8f\xcc\xae\xcc\xae\xcc'
                   u'\x83\xcc\xbe\xe2\x80\xa2\xcc\x83\xcc\xbe)\xdb\xb6 unicode2')
        }
        self.assertEqual(result, expected)

    def test_get_rendered_params_with_casting_unicode_values(self):
        runner_params = {}
        action_params = {'a1': 'unicode1 ٩(̾●̮̮̃̾•̃̾)۶ unicode2'}

        runner_param_info = {}
        action_param_info = {'a1': {'type': 'string'}}

        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)

        expected_action_params = {
            'a1': (u'unicode1 \xd9\xa9(\xcc\xbe\xe2\x97\x8f\xcc\xae\xcc\xae\xcc'
                   u'\x83\xcc\xbe\xe2\x80\xa2\xcc\x83\xcc\xbe)\xdb\xb6 unicode2')
        }
        self.assertEqual(r_runner_params, {})
        self.assertEqual(r_action_params, expected_action_params)

    def test_get_rendered_params_with_dict(self):
        # Note : In this test runner_params.r1 has a string value. However per runner_param_info the
        # type is an integer. The expected type is considered and cast is performed accordingly.
        runner_params = {'r1': '{{r2}}', 'r2': {'r2.1': 1}}
        action_params = {'a1': True, 'a2': '{{a1}}'}
        runner_param_info = {'r1': {'type': 'object'}, 'r2': {'type': 'object'}}
        action_param_info = {'a1': {'type': 'boolean'}, 'a2': {'type': 'boolean'}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': {'r2.1': 1}, 'r2': {'r2.1': 1}})
        self.assertEqual(r_action_params, {'a1': True, 'a2': True})

    def test_get_rendered_params_with_list(self):
        # Note : In this test runner_params.r1 has a string value. However per runner_param_info the
        # type is an integer. The expected type is considered and cast is performed accordingly.
        runner_params = {'r1': '{{r2}}', 'r2': ['1', '2']}
        action_params = {'a1': True, 'a2': '{{a1}}'}
        runner_param_info = {'r1': {'type': 'array'}, 'r2': {'type': 'array'}}
        action_param_info = {'a1': {'type': 'boolean'}, 'a2': {'type': 'boolean'}}
        r_runner_params, r_action_params = param_utils.get_rendered_params(
            runner_params, action_params, runner_param_info, action_param_info)
        self.assertEqual(r_runner_params, {'r1': ['1', '2'], 'r2': ['1', '2']})
        self.assertEqual(r_action_params, {'a1': True, 'a2': True})

    def test_get_rendered_params_with_cyclic_dependency(self):
        runner_params = {'r1': '{{r2}}', 'r2': '{{r1}}'}
        test_pass = True
        try:
            param_utils.get_rendered_params(runner_params, {}, {}, {})
            test_pass = False
        except actionrunner.ActionRunnerException as e:
            test_pass = e.message.find('Cyclic') == 0
        self.assertTrue(test_pass)

    def test_get_rendered_params_with_missing_dependency(self):
        runner_params = {'r1': '{{r3}}', 'r2': '{{r3}}'}
        test_pass = True
        try:
            param_utils.get_rendered_params(runner_params, {}, {}, {})
            test_pass = False
        except actionrunner.ActionRunnerException as e:
            test_pass = e.message.find('Dependecy') == 0
        self.assertTrue(test_pass)

    def _get_action_exec_db_model(self, params):
        actionexec_db = ActionExecutionDB()
        actionexec_db.status = 'initializing'
        actionexec_db.start_timestamp = datetime.datetime.utcnow()
        actionexec_db.action = ResourceReference(name=ParamsUtilsTest.action_db.name,
                                                 pack=ParamsUtilsTest.action_db.pack).ref
        actionexec_db.parameters = params

        return actionexec_db
<|endoftext|>


<commit_before># Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.

from __future__ import absolute_import
import datetime

__all__ = [
    'to_human_time_from_seconds'
]

def to_human_time_from_seconds(seconds):
    """
    Given a time value in seconds, this function returns
    a fuzzy version like 3m5s.

    :param time_seconds: Time specified in seconds.
    :type time_seconds: ``int`` or ``long`` or ``float``

    :rtype: ``str``
    """
    assert (isinstance(seconds, int) or isinstance(seconds, int) or
            isinstance(seconds, float))

    return _get_human_time(seconds)

def _get_human_time(seconds):
    """
    Takes number of seconds as input and returns a string of form '1h3m5s'.

    :param seconds: Number of seconds.
    :type seconds: ``int`` or ``long`` or ``float``

    :rtype: ``str``
    """

    if seconds is None:
        return None

    if seconds == 0:
        return '0s'

    if seconds < 1:
        return '%s\u03BCs' % seconds  # Microseconds

    if isinstance(seconds, float):
        seconds = int(round(seconds))  # Let's lose microseconds.

    timedelta = datetime.timedelta(seconds=seconds)
    offset_date = datetime.datetime(1, 1, 1) + timedelta

    years = offset_date.year - 1
    days = offset_date.day - 1
    hours = offset_date.hour
    mins = offset_date.minute
    secs = offset_date.second

    time_parts = [years, days, hours, mins, secs]

    first_non_zero_pos = next((i for i, x in enumerate(time_parts) if x), None)

    if first_non_zero_pos is None:
        return '0s'
    else:
        time_parts = time_parts[first_non_zero_pos:]

    if len(time_parts) == 1:
        return '%ss' % tuple(time_parts)
    elif len(time_parts) == 2:
        return '%sm%ss' % tuple(time_parts)
    elif len(time_parts) == 3:
        return '%sh%sm%ss' % tuple(time_parts)
    elif len(time_parts) == 4:
        return '%sd%sh%sm%ss' % tuple(time_parts)
    elif len(time_parts) == 5:
        return '%sy%sd%sh%sm%ss' % tuple(time_parts)
<commit_msg>alias long_int to int in Python 3 and long in Python 2<commit_after># Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.

from __future__ import absolute_import
import datetime
import six

__all__ = [
    'to_human_time_from_seconds'
]

if six.PY3:
    long_int = int
else:
    long_int = long

def to_human_time_from_seconds(seconds):
    """
    Given a time value in seconds, this function returns
    a fuzzy version like 3m5s.

    :param time_seconds: Time specified in seconds.
    :type time_seconds: ``int`` or ``long`` or ``float``

    :rtype: ``str``
    """
    assert (isinstance(seconds, int) or isinstance(seconds, int) or
            isinstance(seconds, float))

    return _get_human_time(seconds)

def _get_human_time(seconds):
    """
    Takes number of seconds as input and returns a string of form '1h3m5s'.

    :param seconds: Number of seconds.
    :type seconds: ``int`` or ``long`` or ``float``

    :rtype: ``str``
    """

    if seconds is None:
        return None

    if seconds == 0:
        return '0s'

    if seconds < 1:
        return '%s\u03BCs' % seconds  # Microseconds

    if isinstance(seconds, float):
        seconds = long_int(round(seconds))  # Let's lose microseconds.

    timedelta = datetime.timedelta(seconds=seconds)
    offset_date = datetime.datetime(1, 1, 1) + timedelta

    years = offset_date.year - 1
    days = offset_date.day - 1
    hours = offset_date.hour
    mins = offset_date.minute
    secs = offset_date.second

    time_parts = [years, days, hours, mins, secs]

    first_non_zero_pos = next((i for i, x in enumerate(time_parts) if x), None)

    if first_non_zero_pos is None:
        return '0s'
    else:
        time_parts = time_parts[first_non_zero_pos:]

    if len(time_parts) == 1:
        return '%ss' % tuple(time_parts)
    elif len(time_parts) == 2:
        return '%sm%ss' % tuple(time_parts)
    elif len(time_parts) == 3:
        return '%sh%sm%ss' % tuple(time_parts)
    elif len(time_parts) == 4:
        return '%sd%sh%sm%ss' % tuple(time_parts)
    elif len(time_parts) == 5:
        return '%sy%sd%sh%sm%ss' % tuple(time_parts)
<|endoftext|>


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

import logging

class Production(object):
    DEBUG = False
    SECRET_KEY = '##CHANGEME##'
    SQLALCHEMY_DATABASE_URI = 'postgresql://massa:secret@localhost/massa'
    SQLALCHEMY_ECHO = False
    LOGGER_FILENAME = 'massa.log'

class Development(Production):
    DEBUG = True
    LOGGER_LEVEL = logging.DEBUG
<commit_msg>Define config variable `TESTING`.<commit_after># -*- coding: utf-8 -*-

import logging

class Production(object):
    DEBUG = False
    TESTING = False
    SECRET_KEY = '##CHANGEME##'
    SQLALCHEMY_DATABASE_URI = 'postgresql://massa:secret@localhost/massa'
    SQLALCHEMY_ECHO = False
    LOGGER_FILENAME = 'massa.log'

class Development(Production):
    DEBUG = True
    LOGGER_LEVEL = logging.DEBUG
<|endoftext|>


<commit_before>'''The fitting module define some classes to easily perform 1D curve
   fitting.
'''
from scipy import optimize
from scipy.special import wofz
import numpy as np

def fit(y, x = None, fit_type='Gaussian'):
  '''Static method to perform curve fitting directly.

  For instance, to fit some (x,y) data with a gaussian function, simply use:
  ::

    F = fit(y, x, fit_type='Gaussian')

  '''
  if fit_type == 'Gaussian':
    F = Gaussian()
  elif fit_type == 'Lorentzian':
    F = Lorentzian()
  elif fit_type == 'Cosine':
    F = Cosine()
  else:
    print('unknown fitting type: %s' % fit_type)
    return None
  F.fit(y, x)
  return F

class Parameter:
  '''A class to handle modiable parameters.'''

  def __init__(self, value, name = None):
    '''Create a new parameter with the given value.'''
    self.value = value
    self.name = name

  def set(self, value):
    '''Set the value of the parameter.'''
    self.value = value

  def set_name(self, name):
    '''Set the name of the parameter.'''
    self.name = name

  def __call__(self):
    '''With this we can use p() if p is an instance of Parameter.'''
    return self.value

  def __repr__(self):
    '''Provide a string representation of the parameter, simply based
    on its actual value.'''
    return str(self.value)

class FitFunction:
  '''This class provides a basic canvas to define a fit function.

  You may subclass it to create your own fitting function just as the
  predfined fit function do (see `Gaussian` for instance).
  '''

  def __init__(self):
    self.parameters = []

  def get_parameters(self):
    '''Return the list of parameters of this fit function.'''
    return self.parameters

  def get_parameter_names(self):
    '''Return the list os parameter names of this fit function.'''
    names = []
    for p in self.get_parameters:
      names.append(p.name)
    return names

  def add_parameter(self, value, name):
    param = Parameter(value, name)
    self.parameters.append(param)

  def __call__(self, x):
    '''With this we can call directly f(x) to evaluate the function f at x.'''
    return self.compute(x)

  def __repr__(self):
    '''Provide a string representation of the fitting function, giving
    its type and the list of its parameters with names and values.'''
    s = '%s function\n' % self.__class__.__name__
    s += 'Parameters are:\n'
    params = self.get_parameters()
    for i in range(len(params)):
      s += ' * %s = %g\n' % (params[i].name, params[i].value)
    return s

  def fit(self, y, x = None, verbose = False):
    '''Perform fitting on the given data.

    This will adjust the parameters of this fit function to match as
    well as possible the given data using a least square minimisation.

    *Parameters*

    **y**: the data to match (a 1d numpy array)

    **x**: the corresponding x coordinates (optional, None by default)

    **verbose**: boolean, activate verbose mode
    '''
      # local function to evaluate the cost
      global it
      it = 0
      def cost_func(new_params):
        global it
        p = self.get_parameters()
        if verbose:
          print 'iteration %d, trying parameters:' % it, p
          from matplotlib import pyplot as plt
          if it == 0:
            plt.plot(x, y, 'bo', label = 'data points')
            plt.ylim(0, 0.6)
            plt.grid()
            plt.legend(numpoints=1,loc='upper left')
            plt.savefig('fit/fit_%02d.pdf' % it)
          it += 1
          plt.clf()
          plt.plot(x, y, 'bo', label = 'data points')
          plt.plot(x, self(x), 'k-', label = 'gaussian fit')
          plt.ylim(0, 0.6)
          plt.title('fitting iteration %02d' % it)
          plt.legend(numpoints=1,loc='upper left')
          plt.savefig('fit/fit_%02d.pdf' % it)
        for i, pi in enumerate(p):
          pi.set(new_params[i])
        return y - self(x)

      if x is None: x = np.arange(y.shape[0])
      p = [param.value for param in self.get_parameters()]
      optimize.leastsq(cost_func, p, Dfun= None)

class Gaussian(FitFunction):
  '''first parameter is position, second is sigma, third is height'''
  def __init__(self, position=0.0, sigma=1.0, height=1.0):
    FitFunction.__init__(self)
    self.add_parameter(position, 'position')
    self.add_parameter(sigma, 'sigma')
    self.add_parameter(height, 'height')

  def set_position(self, position):
    '''Set the position (center) of the gauss function.'''
    self.parameters[0].set(position)

  def set_sigma(self, sigma):
    '''Set the width (variance) of the gauss function.'''
    self.parameters[1].set(sigma)

  def set_height(self, height):
    '''Set the maximum (height) of the gauss function.'''
    self.parameters[2].set(height)

  def fwhm(self):
    '''Compute the full width at half maximum of the gauss function.'''
    p = self.get_parameters()
    return 2*p[1].value*np.log(2)

  def compute(self, x):
    '''Evaluate the gauss function at coordinates x.'''
    p = self.get_parameters()
    return p[2].value * np.exp(-((x-p[0].value)/p[1].value)**2)

class Lorentzian(FitFunction):
  '''first parameter is position, second is gamma'''
  def __init__(self, position=0.0, gamma=1.0):
    FitFunction.__init__(self)
    self.add_parameter(position, 'position')
    self.add_parameter(gamma, 'width')

  def set_position(self, position):
    self.parameters[0].set(position)

  def set_gamma(self, gamma):
    self.parameters[1].set(gamma)

  def fwhm(self):
    p = self.get_parameters()
    return 2*p[1].value

  def compute(self, x):
    p = self.get_parameters()
    return p[1].value/np.pi/((x-p[0].value)**2 + p[1].value**2)

class Cosine(FitFunction):
  '''first parameter is position, second is width'''
  def __init__(self, position=0.0, width=1.0):
    FitFunction.__init__(self)
    self.add_parameter(position, 'position')
    self.add_parameter(width, 'width')

  def set_position(self, position):
    self.parameters[0].set(position)

  def set_width(self, a):
    self.parameters[1].set(a)

  def fwhm(self):
    p = self.get_parameters()
    return 3./4*p[1].value

  def compute(self, x):
    p = self.get_parameters()
    return np.cos(np.pi*(x-p[0].value)/(2*p[1].value))

def voigt(x, sigma, gamma):
   # The Voigt function is also the real part of
   # w(z) = exp(-z^2) erfc(iz), the complex probability function,
   # which is also known as the Faddeeva function. Scipy has
   # implemented this function under the name wofz()
   z = (x + 1j*gamma) / (sigma * np.sqrt(2))
   I = wofz(z).real / (sigma * np.sqrt(2) * np.pi)
   return I
<commit_msg>added a general use fit method<commit_after>'''The fitting module define some classes to easily perform 1D curve
   fitting.
'''
from scipy import optimize
from scipy.special import wofz
import numpy as np

def fit(y, x = None, fit_type='Gaussian'):
  '''Static method to perform curve fitting directly.

  For instance, to fit some (x,y) data with a gaussian function, simply use:
  ::

    F = fit(y, x, fit_type='Gaussian')

  '''
  if fit_type == 'Gaussian':
    F = Gaussian()
  elif fit_type == 'Lorentzian':
    F = Lorentzian()
  elif fit_type == 'Cosine':
    F = Cosine()
  else:
    print('unknown fitting type: %s' % fit_type)
    return None
  F.fit(y, x)
  return F

class Parameter:
  '''A class to handle modiable parameters.'''

  def __init__(self, value, name = None):
    '''Create a new parameter with the given value.'''
    self.value = value
    self.name = name

  def set(self, value):
    '''Set the value of the parameter.'''
    self.value = value

  def set_name(self, name):
    '''Set the name of the parameter.'''
    self.name = name

  def __call__(self):
    '''With this we can use p() if p is an instance of Parameter.'''
    return self.value

  def __repr__(self):
    '''Provide a string representation of the parameter, simply based
    on its actual value.'''
    return str(self.value)

class FitFunction:
  '''This class provides a basic canvas to define a fit function.

  You may subclass it to create your own fitting function just as the
  predfined fit function do (see `Gaussian` for instance).
  '''

  def __init__(self):
    self.parameters = []

  def get_parameters(self):
    '''Return the list of parameters of this fit function.'''
    return self.parameters

  def get_parameter_names(self):
    '''Return the list os parameter names of this fit function.'''
    names = []
    for p in self.get_parameters:
      names.append(p.name)
    return names

  def add_parameter(self, value, name):
    param = Parameter(value, name)
    self.parameters.append(param)

  def __call__(self, x):
    '''With this we can call directly f(x) to evaluate the function f at x.'''
    return self.compute(x)

  def __repr__(self):
    '''Provide a string representation of the fitting function, giving
    its type and the list of its parameters with names and values.'''
    s = '%s function\n' % self.__class__.__name__
    s += 'Parameters are:\n'
    params = self.get_parameters()
    for i in range(len(params)):
      s += ' * %s = %g\n' % (params[i].name, params[i].value)
    return s

  def fit(self, y, x = None, verbose = False):
    '''Perform fitting on the given data.

    This will adjust the parameters of this fit function to match as
    well as possible the given data using a least square minimisation.

    *Parameters*

    **y**: the data to match (a 1d numpy array)

    **x**: the corresponding x coordinates (optional, None by default)

    **verbose**: boolean, activate verbose mode
    '''
    # local function to evaluate the cost
    global it
    it = 0
    def cost_func(new_params):
      global it
      p = self.get_parameters()
      if verbose:
        print 'iteration %d, trying parameters:' % it, p
        from matplotlib import pyplot as plt
        if it == 0:
          plt.plot(x, y, 'bo', label = 'data points')
          plt.ylim(0, 0.6)
          plt.grid()
          plt.legend(numpoints=1,loc='upper left')
          plt.savefig('fit/fit_%02d.pdf' % it)
        it += 1
        plt.clf()
        plt.plot(x, y, 'bo', label = 'data points')
        plt.plot(x, self(x), 'k-', label = 'gaussian fit')
        plt.ylim(0, 0.6)
        plt.title('fitting iteration %02d' % it)
        plt.legend(numpoints=1,loc='upper left')
        plt.savefig('fit/fit_%02d.pdf' % it)
      for i, pi in enumerate(p):
        pi.set(new_params[i])
      return y - self(x)

    if x is None: x = np.arange(y.shape[0])
    p = [param.value for param in self.get_parameters()]
    optimize.leastsq(cost_func, p, Dfun= None)

class Gaussian(FitFunction):
  '''first parameter is position, second is sigma, third is height'''
  def __init__(self, position=0.0, sigma=1.0, height=1.0):
    FitFunction.__init__(self)
    self.add_parameter(position, 'position')
    self.add_parameter(sigma, 'sigma')
    self.add_parameter(height, 'height')

  def set_position(self, position):
    '''Set the position (center) of the gauss function.'''
    self.parameters[0].set(position)

  def set_sigma(self, sigma):
    '''Set the width (variance) of the gauss function.'''
    self.parameters[1].set(sigma)

  def set_height(self, height):
    '''Set the maximum (height) of the gauss function.'''
    self.parameters[2].set(height)

  def fwhm(self):
    '''Compute the full width at half maximum of the gauss function.'''
    p = self.get_parameters()
    return 2*p[1].value*np.log(2)

  def compute(self, x):
    '''Evaluate the gauss function at coordinates x.'''
    p = self.get_parameters()
    return p[2].value * np.exp(-((x-p[0].value)/p[1].value)**2)

class Lorentzian(FitFunction):
  '''first parameter is position, second is gamma'''
  def __init__(self, position=0.0, gamma=1.0):
    FitFunction.__init__(self)
    self.add_parameter(position, 'position')
    self.add_parameter(gamma, 'width')

  def set_position(self, position):
    self.parameters[0].set(position)

  def set_gamma(self, gamma):
    self.parameters[1].set(gamma)

  def fwhm(self):
    p = self.get_parameters()
    return 2*p[1].value

  def compute(self, x):
    p = self.get_parameters()
    return p[1].value/np.pi/((x-p[0].value)**2 + p[1].value**2)

class Cosine(FitFunction):
  '''first parameter is position, second is width'''
  def __init__(self, position=0.0, width=1.0):
    FitFunction.__init__(self)
    self.add_parameter(position, 'position')
    self.add_parameter(width, 'width')

  def set_position(self, position):
    self.parameters[0].set(position)

  def set_width(self, a):
    self.parameters[1].set(a)

  def fwhm(self):
    p = self.get_parameters()
    return 3./4*p[1].value

  def compute(self, x):
    p = self.get_parameters()
    return np.cos(np.pi*(x-p[0].value)/(2*p[1].value))

def voigt(x, sigma, gamma):
   # The Voigt function is also the real part of
   # w(z) = exp(-z^2) erfc(iz), the complex probability function,
   # which is also known as the Faddeeva function. Scipy has
   # implemented this function under the name wofz()
   z = (x + 1j*gamma) / (sigma * np.sqrt(2))
   I = wofz(z).real / (sigma * np.sqrt(2) * np.pi)
   return I
<|endoftext|>


<commit_before>from functools import wraps
from collections import defaultdict
from django import http
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, render
from django.core.exceptions import PermissionDenied
from django.contrib.auth.views import login
from django.contrib.auth.decorators import login_required
from mdpage.models import MarkdownPage, MarkdownPageType, mdpage_conf
from mdpage import forms
from mdpage.auth_utils import login_user

#-------------------------------------------------------------------------------
def get_page(prefix, slug, raise_404=True):
    mdp_type = get_object_or_404(MarkdownPageType.published, prefix=prefix)
    try:
        page = MarkdownPage.published.get(type=mdp_type, slug=slug)
    except MarkdownPage.DoesNotExist:
        if raise_404:
            raise

        page = None

    return mdp_type, page

#-------------------------------------------------------------------------------
def mdpage_render(request, mdp_type, tmpl, data=None):
    return render(request, tmpl, dict(data or {}, mdp_type=mdp_type))

#-------------------------------------------------------------------------------
def page_redirect(page):
    return http.HttpResponseRedirect(page.get_absolute_url())

#-------------------------------------------------------------------------------
def _listing(pages):
    count = len(pages)
    listing = defaultdict(list)
    for page in pages:
        listing[page.title[0].upper()].append(page)

    return count, sorted(listing.items())

#-------------------------------------------------------------------------------
def _mdpage_list_tags(request, mdp_type, **opts):
    tag = opts.get('tag')
    if tag:
        count, listing = _listing(mdp_type.tagged_by(tag))
        return mdpage_render(request, mdp_type, 'mdpage/home.html', {
            'listing': listing,
            'count': count,
            'title': 'Pages for topic "{}"'.format(tag)
        })

    else:
        return mdpage_render(request, mdp_type, 'mdpage/tags.html', {'mdp_type': mdp_type})

#-------------------------------------------------------------------------------
def _mdpage_edit_tags(request, mdp_type, **opts):
    pages = mdp_type.markdownpage_set.order_by('title')
    if request.method == 'POST':
        pages_dict = dict([('page_%s' % p.pk, p) for p in pages])
        for key, value in request.POST.items():
            page = pages_dict[key]
            page.tags = value
        return http.HttpResponseRedirect('%s?tag-edit' % (reverse('mdpage_home'),))

    data = dict(pages=pages)
    return mdpage_render(request, mdp_type, 'mdpage/edit_tags.html', data)

#-------------------------------------------------------------------------------
def mdpage_edit(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)

    data = {'page': page}
    if request.method == 'POST':
        if 'cancel' in request.POST:
            page.unlock(request)
            return page_redirect(page)

        form =  forms.MarkdownPageForm(request.POST, instance=page)
        if form.is_valid():
            return page_redirect(form.save(request))
    else:
        if page.lock(request):
            page.unlock(request)
            # return mdpage_render(request, mdp_type, 'mdpage/locked.html', data)

        form = forms.MarkdownPageForm(instance=page)
    data['form'] = form
    return mdpage_render(request, mdp_type, 'mdpage/edit.html', data)

#-------------------------------------------------------------------------------
@login_required
def _mdpage_new_page(request, mdp_type, title):
    page = MarkdownPage(type=mdp_type, title=title)
    data = {'page': page}

    if request.POST:
        form = forms.MarkdownPageForm(request.POST, instance=page)
        if form.is_valid():
            return page_redirect(form.save(request))
    else:
        form = forms.MarkdownPageForm(instance=page)

    data['form'] = form
    return mdpage_render(request, mdp_type, 'mdpage/edit.html', data)

#-------------------------------------------------------------------------------
def _mdpage_get_or_create_page(request, mdp_type, **opts):
    title = opts.get('new', '')
    page = mdp_type.markdownpage_set.find(title)
    if page:
        return page_redirect(page)

    return _mdpage_new_page(request, mdp_type, title)

#-------------------------------------------------------------------------------
def _mdpage_page_listing(request, mdp_type, **opts):
    count, listing = _listing(mdp_type.markdownpage_set.order_by('title'))
    return mdpage_render(request, mdp_type, 'mdpage/home.html', {
        'listing': listing,
        'count': count,
        'title': 'Page Listing'
    })

#-------------------------------------------------------------------------------
def _mdpage_search(request, mdp_type, **opts):
    words = request.GET['search'].split()
    return mdpage_render(request, mdp_type, 'mdpage/search.html', {
        'pages': mdp_type.markdownpage_set.search(words),
        'words': words
    })

#-------------------------------------------------------------------------------
def _mdpage_recent_updates(request, mdp_type, **opts):
    return mdpage_render(request, mdp_type, 'mdpage/recent.html', {
        'pages': mdp_type.markdownpage_set.order_by('-updated')
    })

HOME_OPTIONS = (
    ('search',   _mdpage_search),
    ('new',      _mdpage_get_or_create_page),
    ('recent',   _mdpage_recent_updates),
    ('tag',      _mdpage_list_tags),
    ('tag-edit', _mdpage_edit_tags),
    ('list',     _mdpage_page_listing),
)

################################################################################

#-------------------------------------------------------------------------------
def mdpage_listing(request, prefix):
    mdp_type = get_object_or_404(MarkdownPageType.published, prefix=prefix)
    for key,func in HOME_OPTIONS:
        if key in request.GET:
            return func(request, **{'mdp_type': mdp_type, key : request.GET.get(key)})

    mdp_type, page = get_page(prefix, mdpage_conf.home_title, False)
    if not page:
        return _mdpage_page_listing(request, mdp_type)

    return mdpage_render(request, mdp_type, 'mdpage/page.html', {
        'page': page,
        'mdp_type': mdp_type
    })

#-------------------------------------------------------------------------------
def mdpage_history(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)
    return mdpage_render(request, mdp_type, 'mdpage/history.html', {'page': page})

#-------------------------------------------------------------------------------
def mdpage_version(request, prefix, slug, version):
    mdp_type, page = get_page(prefix, slug)
    archive = page.markdownpagearchive_set.get(id=version)
    return mdpage_render(request, mdp_type, 'mdpage/history.html', {'page': page, 'archive': archive})

#-------------------------------------------------------------------------------
def mdpage_view(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug, False)
    if page:
        return mdpage_render(request, mdp_type, 'mdpage/page.html', {
            'page': page,
            'mdp_type': mdp_type
        })

    if not mdp_type or not request.user.is_authenticated():
        raise http.Http404('Page not found')

    return _mdpage_new_page(
        request,
        get_object_or_404(MarkdownPageType, slug=prefix),
        new=slug.capitalize()
    )

#-------------------------------------------------------------------------------
def mdpage_text(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)
    return http.HttpResponse(page.text, content_type="text/plain; charset=utf8")

#-------------------------------------------------------------------------------
def mdpage_attach(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)
    if request.method == 'POST':
        form =  forms.ContentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save(page)
            return page_redirect(page)
    else:
        form =  forms.ContentForm()

    return mdpage_render(request, mdp_type, 'mdpage/attach.html', {'page': page, 'form': form})

<commit_msg>fixed reference to auth_utils<commit_after>from functools import wraps
from collections import defaultdict
from django import http
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, render
from django.core.exceptions import PermissionDenied
from django.contrib.auth.views import login
from django.contrib.auth.decorators import login_required
from mdpage.models import MarkdownPage, MarkdownPageType, mdpage_conf
from mdpage import forms

#-------------------------------------------------------------------------------
def get_page(prefix, slug, raise_404=True):
    mdp_type = get_object_or_404(MarkdownPageType.published, prefix=prefix)
    try:
        page = MarkdownPage.published.get(type=mdp_type, slug=slug)
    except MarkdownPage.DoesNotExist:
        if raise_404:
            raise

        page = None

    return mdp_type, page

#-------------------------------------------------------------------------------
def mdpage_render(request, mdp_type, tmpl, data=None):
    return render(request, tmpl, dict(data or {}, mdp_type=mdp_type))

#-------------------------------------------------------------------------------
def page_redirect(page):
    return http.HttpResponseRedirect(page.get_absolute_url())

#-------------------------------------------------------------------------------
def _listing(pages):
    count = len(pages)
    listing = defaultdict(list)
    for page in pages:
        listing[page.title[0].upper()].append(page)

    return count, sorted(listing.items())

#-------------------------------------------------------------------------------
def _mdpage_list_tags(request, mdp_type, **opts):
    tag = opts.get('tag')
    if tag:
        count, listing = _listing(mdp_type.tagged_by(tag))
        return mdpage_render(request, mdp_type, 'mdpage/home.html', {
            'listing': listing,
            'count': count,
            'title': 'Pages for topic "{}"'.format(tag)
        })

    else:
        return mdpage_render(request, mdp_type, 'mdpage/tags.html', {'mdp_type': mdp_type})

#-------------------------------------------------------------------------------
def _mdpage_edit_tags(request, mdp_type, **opts):
    pages = mdp_type.markdownpage_set.order_by('title')
    if request.method == 'POST':
        pages_dict = dict([('page_%s' % p.pk, p) for p in pages])
        for key, value in request.POST.items():
            page = pages_dict[key]
            page.tags = value
        return http.HttpResponseRedirect('%s?tag-edit' % (reverse('mdpage_home'),))

    data = dict(pages=pages)
    return mdpage_render(request, mdp_type, 'mdpage/edit_tags.html', data)

#-------------------------------------------------------------------------------
def mdpage_edit(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)

    data = {'page': page}
    if request.method == 'POST':
        if 'cancel' in request.POST:
            page.unlock(request)
            return page_redirect(page)

        form =  forms.MarkdownPageForm(request.POST, instance=page)
        if form.is_valid():
            return page_redirect(form.save(request))
    else:
        if page.lock(request):
            page.unlock(request)
            # return mdpage_render(request, mdp_type, 'mdpage/locked.html', data)

        form = forms.MarkdownPageForm(instance=page)
    data['form'] = form
    return mdpage_render(request, mdp_type, 'mdpage/edit.html', data)

#-------------------------------------------------------------------------------
@login_required
def _mdpage_new_page(request, mdp_type, title):
    page = MarkdownPage(type=mdp_type, title=title)
    data = {'page': page}

    if request.POST:
        form = forms.MarkdownPageForm(request.POST, instance=page)
        if form.is_valid():
            return page_redirect(form.save(request))
    else:
        form = forms.MarkdownPageForm(instance=page)

    data['form'] = form
    return mdpage_render(request, mdp_type, 'mdpage/edit.html', data)

#-------------------------------------------------------------------------------
def _mdpage_get_or_create_page(request, mdp_type, **opts):
    title = opts.get('new', '')
    page = mdp_type.markdownpage_set.find(title)
    if page:
        return page_redirect(page)

    return _mdpage_new_page(request, mdp_type, title)

#-------------------------------------------------------------------------------
def _mdpage_page_listing(request, mdp_type, **opts):
    count, listing = _listing(mdp_type.markdownpage_set.order_by('title'))
    return mdpage_render(request, mdp_type, 'mdpage/home.html', {
        'listing': listing,
        'count': count,
        'title': 'Page Listing'
    })

#-------------------------------------------------------------------------------
def _mdpage_search(request, mdp_type, **opts):
    words = request.GET['search'].split()
    return mdpage_render(request, mdp_type, 'mdpage/search.html', {
        'pages': mdp_type.markdownpage_set.search(words),
        'words': words
    })

#-------------------------------------------------------------------------------
def _mdpage_recent_updates(request, mdp_type, **opts):
    return mdpage_render(request, mdp_type, 'mdpage/recent.html', {
        'pages': mdp_type.markdownpage_set.order_by('-updated')
    })

HOME_OPTIONS = (
    ('search',   _mdpage_search),
    ('new',      _mdpage_get_or_create_page),
    ('recent',   _mdpage_recent_updates),
    ('tag',      _mdpage_list_tags),
    ('tag-edit', _mdpage_edit_tags),
    ('list',     _mdpage_page_listing),
)

################################################################################

#-------------------------------------------------------------------------------
def mdpage_listing(request, prefix):
    mdp_type = get_object_or_404(MarkdownPageType.published, prefix=prefix)
    for key,func in HOME_OPTIONS:
        if key in request.GET:
            return func(request, **{'mdp_type': mdp_type, key : request.GET.get(key)})

    mdp_type, page = get_page(prefix, mdpage_conf.home_title, False)
    if not page:
        return _mdpage_page_listing(request, mdp_type)

    return mdpage_render(request, mdp_type, 'mdpage/page.html', {
        'page': page,
        'mdp_type': mdp_type
    })

#-------------------------------------------------------------------------------
def mdpage_history(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)
    return mdpage_render(request, mdp_type, 'mdpage/history.html', {'page': page})

#-------------------------------------------------------------------------------
def mdpage_version(request, prefix, slug, version):
    mdp_type, page = get_page(prefix, slug)
    archive = page.markdownpagearchive_set.get(id=version)
    return mdpage_render(request, mdp_type, 'mdpage/history.html', {'page': page, 'archive': archive})

#-------------------------------------------------------------------------------
def mdpage_view(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug, False)
    if page:
        return mdpage_render(request, mdp_type, 'mdpage/page.html', {
            'page': page,
            'mdp_type': mdp_type
        })

    if not mdp_type or not request.user.is_authenticated():
        raise http.Http404('Page not found')

    return _mdpage_new_page(
        request,
        get_object_or_404(MarkdownPageType, slug=prefix),
        new=slug.capitalize()
    )

#-------------------------------------------------------------------------------
def mdpage_text(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)
    return http.HttpResponse(page.text, content_type="text/plain; charset=utf8")

#-------------------------------------------------------------------------------
def mdpage_attach(request, prefix, slug):
    mdp_type, page = get_page(prefix, slug)
    if request.method == 'POST':
        form =  forms.ContentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save(page)
            return page_redirect(page)
    else:
        form =  forms.ContentForm()

    return mdpage_render(request, mdp_type, 'mdpage/attach.html', {'page': page, 'form': form})

<|endoftext|>


<commit_before>class EmitterError(Exception):
  pass

def emit_hostmask(nickname, username, host):
  return "{}!{}@{}".format(nickname, username, host)

def emit_message(prefix, command, params, force_trailing=False):
  buf = []

  if prefix is not None:
    buf.append(":" + prefix)

  buf.append(command)

  if params:
    *init, last = params

    for param in init:
      if " " in param:
        raise EmitterError("malformed message")

    if force_trailing or not last or " " in last or last[0] == ":":
      buf.extend(init)
      buf.append(":" + last)
    else:
      buf.extend(params)

  return " ".join(buf).encode("utf-8")
<commit_msg>Allow omitting nickname in the hostmask emitter.<commit_after>class EmitterError(Exception):
  pass

def emit_hostmask(nickname, username, host):
  if nickname is None:
    return "{}@{}".format(username, host)
  return "{}!{}@{}".format(nickname, username, host)

def emit_message(prefix, command, params, force_trailing=False):
  buf = []

  if prefix is not None:
    buf.append(":" + prefix)

  buf.append(command)

  if params:
    *init, last = params

    for param in init:
      if " " in param:
        raise EmitterError("malformed message")

    if force_trailing or not last or " " in last or last[0] == ":":
      buf.extend(init)
      buf.append(":" + last)
    else:
      buf.extend(params)

  return " ".join(buf).encode("utf-8")
<|endoftext|>