<commit_before>"""
diffusions: a module providing segmentation algorithm based on diffusion.

The algorithms of this module are based on the "random walker" algorithm.
"""

# Author: Emmanuelle Gouillart <emmanuelle.gouillart@normalesup.org>
# Copyright (c) 2009-2010, Emmanuelle Gouillart
# License: BSD

import warnings

import numpy as np
from scipy import sparse, ndimage
try:
    from scipy.sparse.linalg.dsolve import umfpack
    u = umfpack.UmfpackContext()
except:
    warnings.warn("""Scipy was built without UMFPACK. Consider rebuilding
    Scipy with UMFPACK, this will greatly speed up the random walker
    functions. You may also install pyamg and run the random walker function
    in amg mode (see the docstrings)
    """)
try:
    from pyamg import smoothed_aggregation_solver
    amg_loaded = True
except ImportError:
    amg_loaded = False
import scipy
scipy_version = scipy.__version__.split('.')

#-----------Laplacian--------------------

def _make_edges_3d(lx, ly, lz):
    """ Returns a list of edges for a 3D image.

        Parameters
        ===========
        lx: integer
            The size of the grid in the x direction.
        ly: integer, optinal
            The size of the grid in the y direction, defaults
            to lx.
        lz: integer, optinal
            The size of the grid in the z direction, defaults
            to lx.
    """
    vertices = np.arange(lx*ly*lz).reshape((lx, ly, lz))
    edges_deep = np.vstack((vertices[:, :, :-1].ravel(),
                            vertices[:, :, 1:].ravel()))
    edges_right = np.vstack((vertices[:, :-1].ravel(), vertices[:, 1:].ravel()))
    edges_down = np.vstack((vertices[:-1].ravel(), vertices[1:].ravel()))
    edges = np.hstack((edges_deep, edges_right, edges_down))
    return edges

def _make_weights_3d(edges, data, beta=130, eps=1.e-6):
    lx, ly, lz = data.shape
    gradients = _make_distances_3d(edges, data)**2
    weights = np.exp(- beta*gradients / (10*data.std())) + eps
    return weights

def _make_distances_3d(edges, data):
    lx, ly, lz = data.shape
    gradients = np.abs(data[edges[0]/(ly*lz), \
                                 (edges[0] % (ly*lz))/lz, \
                                 (edges[0] % (ly*lz))%lz] - \
                            data[edges[1]/(ly*lz), \
                                 (edges[1] % (ly*lz))/lz, \
                                 (edges[1] % (ly*lz)) % lz])
    return gradients

def _make_laplacian_sparse(edges, weights):
    """
    Sparse implementation
    """
    pixel_nb = len(np.unique(edges.ravel()))
    diag = np.arange(pixel_nb)
    i_indices = np.hstack((edges[0], edges[1]))
    j_indices = np.hstack((edges[1], edges[0]))
    data = np.hstack((-weights, -weights))
    lap = sparse.coo_matrix((data, (i_indices, j_indices)),
                            shape=(pixel_nb, pixel_nb))
    connect = - np.ravel(lap.sum(axis=1))
    lap = sparse.coo_matrix((np.hstack((data, connect)),
                (np.hstack((i_indices,diag)), np.hstack((j_indices, diag)))),
                shape=(pixel_nb, pixel_nb))
    return lap.tocsc()

def _clean_labels_ar(X, labels):
    labels = np.ravel(labels)
    labels[labels == 0] = X
    return labels

def _buildAB(lap_sparse, labels):
    lx, ly, lz = labels.shape
    labels = labels.ravel()
    labels = labels[labels >= 0]
    total_ind = np.arange(labels.size)
    unmarked = total_ind[labels == 0]
    seeds_indices = np.setdiff1d(total_ind, unmarked)
    B = lap_sparse[unmarked][:, seeds_indices]
    lap_sparse = lap_sparse[unmarked][:, unmarked]
    nlabels = labels.max()
    Bi = sparse.lil_matrix((nlabels, B.shape[0]))
    for lab in range(1, nlabels+1):
        fs = sparse.csr_matrix((labels[seeds_indices] == lab)\
                                                [:, np.newaxis])
        Bi[lab-1, :] = (B.tocsr()* fs)
    return lap_sparse, Bi

def _trim_edges_weights(edges, weights, mask):
    inds = np.arange(mask.size)
    inds = inds[mask.ravel()]
    ind_mask = np.logical_and(np.in1d(edges[0], inds),
                          np.in1d(edges[1], inds))
    edges, weights = edges[:, ind_mask], weights[ind_mask]
    maxval = edges.max()
    order = np.searchsorted(np.unique(edges.ravel()), np.arange(maxval+1))
    edges = order[edges]
    return edges, weights

def _build_laplacian(data, mask=None, normed=False, beta=50):
    lx, ly, lz = data.shape
    edges = _make_edges_3d(lx, ly, lz)
    weights = _make_weights_3d(edges, data, beta=beta, eps=1.e-10)
    if mask is not None:
        edges, weights = _trim_edges_weights(edges, weights, mask)
    if not normed:
        lap =  _make_laplacian_sparse(edges, weights)
        del edges, weights
        return lap
    else:
        lap, w = _make_normed_laplacian(edges, weights)
        del edges, weights
        return lap, w

#----------- Random walker algorithms (with markers or with prior) -------------

@profile
def random_walker(data, labels, beta=130, mode='bf', copy=True):
    """
        Segmentation with random walker algorithm by Leo Grady,
        given some data and an array of labels (the more labeled
        pixels, the less unknowns and the faster the resolution)

        Parameters
        ----------

        data : array_like
            Image to be segmented in regions. `data` can be two- or
            three-dimensional.

        labels : array of ints
            Array of seed markers labeled with different integers
            for different phases. Negative labels correspond to inactive
            pixels that do not diffuse (they are removed from the graph).

        beta : float
            Penalization coefficient for the random walker motion
            (the greater `beta`, the more difficult the diffusion).

        mode : {'bf', 'amg'}
            Mode for solving the linear system in the random walker
            algorithm. `mode` can be either 'bf' (for brute force),
            in which case matrices are directly inverted, or 'amg'
            (for algebraic multigrid solver), in which case a multigrid
            approach is used. The 'amg' mode uses the pyamg module
            (http://code.google.com/p/pyamg/), which must be installed
            to use this mode.

        copy : bool
            If copy is False, the `labels` array will be overwritten with
            the result of the segmentation. Use copy=False if you want to
            save on memory.

        Returns
        -------

        output : ndarray of ints
            Array in which each pixel has been attributed the label number
            that reached the pixel first by diffusion.

        Notes
        -----

        The algorithm was first proposed in *Random walks for image
        segmentation*, Leo Grady, IEEE Trans Pattern Anal Mach Intell.
        2006 Nov;28(11):1768-83.

        Examples
        --------

        >>> a = np.zeros((10, 10)) + 0.2*np.random.random((10, 10))
        >>> a[5:8, 5:8] += 1
        >>> b = np.zeros_like(a)
        >>> b[3,3] = 1 #Marker for first phase
        >>> b[6,6] = 2 #Marker for second phase
        >>> random_walker(a, b)
        array([[ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]])

    """
    # We work with 3-D arrays
    data = np.atleast_3d(data)
    if copy:
        labels = np.copy(labels)
    labels = labels.astype(np.int)
    # If the array has pruned zones, be sure that no isolated pixels
    # exist between pruned zones (they could not be determined)
    if np.any(labels<0):
        filled = ndimage.binary_propagation(labels>0, mask=labels>=0)
        labels[np.logical_and(np.logical_not(filled), labels == 0)] = -1
        del filled
    labels = np.atleast_3d(labels)
    if np.any(labels < 0):
        lap_sparse = _build_laplacian(data, mask=labels >= 0, beta=beta)
    else:
        lap_sparse = _build_laplacian(data, beta=beta)
    lap_sparse, B = _buildAB(lap_sparse, labels)
    # We solve the linear system
    # lap_sparse X = B
    # where X[i, j] is the probability that a marker of label i arrives
    # first at pixel j by diffusion
    if mode == 'bf':
        lap_sparse = lap_sparse.tocsc()
        solver = sparse.linalg.factorized(lap_sparse.astype(np.double))
        X = np.array([solver(np.array((-B[i, :]).todense()).ravel())\
                for i in range(B.shape[0])])
        X = np.argmax(X, axis=0) + 1
        data = np.squeeze(data)
        return (_clean_labels_ar(X, labels)).reshape(data.shape)
    elif mode == 'amg':
        if not amg_loaded:
            print """the pyamg module (http://code.google.com/p/pyamg/)
            must be installed to use the amg mode"""
            raise ImportError
        lap_sparse = lap_sparse.tocsr()
        le = lap_sparse.shape[0]
        mls = smoothed_aggregation_solver(lap_sparse)
        del lap_sparse
        ll = np.zeros(le, dtype=np.int32)
        proba_max = np.zeros(le, dtype=np.float32)
        for i in range(B.shape[0]):
            x = mls.solve(np.ravel(-B[i, :].todense()).astype(np.float32))
            mask = x > proba_max
            ll[mask] = i
            proba_max[mask] = (x[mask]).astype(np.float32)
            del mask
        del proba_max
        ll = _clean_labels_ar(ll + 1, labels)
        data = np.squeeze(data)
        return ll.reshape(data.shape)

def random_walker_prior(data, prior, mode='bf', gamma=1.e-2):
    """
        Parameters
        ----------

        data : array_like
            Image to be segmented in regions. `data` can be two- or
            three-dimensional.

        prior : array_like
            Array of 1-dimensional probabilities that the pixels
            belong to the different phases. The size of `prior` is n x s
            where n is the number of phases to be segmented, and s the
            total number of pixels.

        mode : {'bf', 'amg'}
            Mode for solving the linear system in the random walker
            algorithm. `mode` can be either 'bf' (for brute force),
            in which case matrices are directly inverted, or 'amg'
            (for algebraic multigrid solver), in which case a multigrid
            approach is used. The 'amg' mode uses the pyamg module
            (http://code.google.com/p/pyamg/), which must be installed
            to use this mode.

        gamma : float
            gamma determines the absence of confidence into the prior.
            The smaller gamma, the more the output values will be determined
            according to the prior only. Conversely, the greater gamma,
            the more continuous the segmented regions will be.

        Returns
        -------

        output : ndarray of ints
            Segmentation of data. The number of phases corresponds to the
            number of lines in prior.

        Notes
        -----

        The algorithm was first proposed in *Multilabel random walker
        image segmentation using prior models*, L. Grady, IEEE CVPR 2005,
        p. 770 (2005).

        Examples
        --------
        >>> a = np.zeros((40, 40))
        >>> a[10:-10, 10:-10] = 1
        >>> a += 0.7*np.random.random((40, 40))
        >>> p = a.max() - a.ravel()
        >>> q = a.ravel()
        >>> prior = np.array([p, q])
        >>> labs = random_walker_prior(a, prior)
    """
    data = np.atleast_3d(data)
    lap_sparse = _build_laplacian(data, beta=50)
    dia = range(data.size)
    shx, shy = lap_sparse.shape
    lap_sparse = lap_sparse + sparse.coo_matrix(
                        (gamma*prior.sum(axis=0), (range(shx), range(shy))))
    del dia
    if mode == 'bf':
        lap_sparse = lap_sparse.tocsc()
        solver = sparse.linalg.factorized(lap_sparse.astype(np.double))
        X = np.array([solver(gamma*label_prior)
                      for label_prior in prior])
    elif mode == 'amg':
        if not amg_loaded:
            print """the pyamg module (http://code.google.com/p/pyamg/)
            must be installed to use the amg mode"""
            raise ImportError
        lap_sparse = lap_sparse.tocsr()
        mls = smoothed_aggregation_solver(lap_sparse)
        del lap_sparse
        X = np.array([mls.solve(gamma*label_prior)
                      for label_prior in prior])
        del mls
    return np.squeeze((np.argmax(X, axis=0)).reshape(data.shape))

<commit_msg>ENH: some cleaning<commit_after>"""
diffusions: a module providing segmentation algorithm based on diffusion.

The algorithms of this module are based on the "random walker" algorithm.
"""

# Author: Emmanuelle Gouillart <emmanuelle.gouillart@normalesup.org>
# Copyright (c) 2009-2010, Emmanuelle Gouillart
# License: BSD

import warnings

import numpy as np
from scipy import sparse, ndimage
try:
    from scipy.sparse.linalg.dsolve import umfpack
    u = umfpack.UmfpackContext()
except:
    warnings.warn("""Scipy was built without UMFPACK. Consider rebuilding
    Scipy with UMFPACK, this will greatly speed up the random walker
    functions. You may also install pyamg and run the random walker function
    in amg mode (see the docstrings)
    """)
try:
    from pyamg import smoothed_aggregation_solver
    amg_loaded = True
except ImportError:
    amg_loaded = False
import scipy
scipy_version = scipy.__version__.split('.')

#-----------Laplacian--------------------

def _make_edges_3d(n_x, n_y, n_z):
    """
    Returns a list of edges for a 3D image.

    Parameters
    ===========
    n_x: integer
        The size of the grid in the x direction.
    n_y: integer
        The size of the grid in the y direction
    n_z: integer
        The size of the grid in the z direction
    """
    vertices = np.arange(n_x * n_y * n_z).reshape((n_x, n_y, n_z))
    edges_deep = np.vstack((vertices[:, :, :-1].ravel(),
                            vertices[:, :, 1:].ravel()))
    edges_right = np.vstack((vertices[:, :-1].ravel(), vertices[:, 1:].ravel()))
    edges_down = np.vstack((vertices[:-1].ravel(), vertices[1:].ravel()))
    edges = np.hstack((edges_deep, edges_right, edges_down))
    return edges

def _compute_weights_3d(edges, data, beta=130, eps=1.e-6):
    l_x, l_y, l_z = data.shape
    gradients = _compute_gradients_3d(edges, data)**2
    weights = np.exp(- beta*gradients / (10*data.std())) + eps
    return weights

def _compute_gradients_3d(edges, data):
    l_x, l_y, l_z = data.shape
    gradients = np.abs(data[edges[0] / (l_y * l_z),
                                 (edges[0] % (l_y * l_z)) / l_z,
                                 (edges[0] % (l_y * l_z)) % l_z] -
                       data[edges[1] / (l_y * l_z), \
                                 (edges[1] % (l_y * l_z)) / l_z, \
                                 (edges[1] % (l_y * l_z)) % l_z])
    return gradients

def _make_laplacian_sparse(edges, weights):
    """
    Sparse implementation
    """
    pixel_nb = len(np.unique(edges.ravel()))
    diag = np.arange(pixel_nb)
    i_indices = np.hstack((edges[0], edges[1]))
    j_indices = np.hstack((edges[1], edges[0]))
    data = np.hstack((-weights, -weights))
    lap = sparse.coo_matrix((data, (i_indices, j_indices)),
                            shape=(pixel_nb, pixel_nb))
    connect = - np.ravel(lap.sum(axis=1))
    lap = sparse.coo_matrix((np.hstack((data, connect)),
                (np.hstack((i_indices,diag)), np.hstack((j_indices, diag)))),
                shape=(pixel_nb, pixel_nb))
    return lap.tocsc()

def _clean_labels_ar(X, labels):
    labels = np.ravel(labels)
    labels[labels == 0] = X
    return labels

def _buildAB(lap_sparse, labels):
    l_x, l_y, l_z = labels.shape
    labels = labels[labels >= 0]
    indices = np.arange(labels.size)
    unlabeled_indices = indices[labels == 0]
    seeds_indices = indices[labels > 0]
    B = lap_sparse[unlabeled_indices][:, seeds_indices]
    lap_sparse = lap_sparse[unlabeled_indices][:, unlabeled_indices]
    nlabels = labels.max()
    Bi = sparse.lil_matrix((nlabels, B.shape[0]))
    for lab in range(1, nlabels+1):
        fs = sparse.csr_matrix((labels[seeds_indices] == lab)\
                                                [:, np.newaxis])
        Bi[lab-1, :] = (B.tocsr()* fs)
    return lap_sparse, Bi

def _trim_edges_weights(edges, weights, mask):
    inds = np.arange(mask.size)
    inds = inds[mask.ravel()]
    ind_mask = np.logical_and(np.in1d(edges[0], inds),
                          np.in1d(edges[1], inds))
    edges, weights = edges[:, ind_mask], weights[ind_mask]
    maxval = edges.max()
    order = np.searchsorted(np.unique(edges.ravel()), np.arange(maxval+1))
    edges = order[edges]
    return edges, weights

def _build_laplacian(data, mask=None, beta=50):
    l_x, l_y, l_z = data.shape
    edges = _make_edges_3d(l_x, l_y, l_z)
    weights = _compute_weights_3d(edges, data, beta=beta, eps=1.e-10)
    if mask is not None:
        edges, weights = _trim_edges_weights(edges, weights, mask)
    lap =  _make_laplacian_sparse(edges, weights)
    del edges, weights
    return lap

#----------- Random walker algorithms (with markers or with prior) -------------

def random_walker(data, labels, beta=130, mode='bf', copy=True):
    """
        Segmentation with random walker algorithm by Leo Grady,
        given some data and an array of labels (the more labeled
        pixels, the less unknowns and the faster the resolution)

        Parameters
        ----------

        data : array_like
            Image to be segmented in regions. `data` can be two- or
            three-dimensional.

        labels : array of ints
            Array of seed markers labeled with different integers
            for different phases. Negative labels correspond to inactive
            pixels that do not diffuse (they are removed from the graph).

        beta : float
            Penalization coefficient for the random walker motion
            (the greater `beta`, the more difficult the diffusion).

        mode : {'bf', 'amg'}
            Mode for solving the linear system in the random walker
            algorithm. `mode` can be either 'bf' (for brute force),
            in which case matrices are directly inverted, or 'amg'
            (for algebraic multigrid solver), in which case a multigrid
            approach is used. The 'amg' mode uses the pyamg module
            (http://code.google.com/p/pyamg/), which must be installed
            to use this mode.

        copy : bool
            If copy is False, the `labels` array will be overwritten with
            the result of the segmentation. Use copy=False if you want to
            save on memory.

        Returns
        -------

        output : ndarray of ints
            Array in which each pixel has been attributed the label number
            that reached the pixel first by diffusion.

        Notes
        -----

        The algorithm was first proposed in *Random walks for image
        segmentation*, Leo Grady, IEEE Trans Pattern Anal Mach Intell.
        2006 Nov;28(11):1768-83.

        Examples
        --------

        >>> a = np.zeros((10, 10)) + 0.2*np.random.random((10, 10))
        >>> a[5:8, 5:8] += 1
        >>> b = np.zeros_like(a)
        >>> b[3,3] = 1 #Marker for first phase
        >>> b[6,6] = 2 #Marker for second phase
        >>> random_walker(a, b)
        array([[ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  2.,  2.,  2.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
               [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]])

    """
    # We work with 3-D arrays
    data = np.atleast_3d(data)
    if copy:
        labels = np.copy(labels)
    labels = labels.astype(np.int)
    # If the array has pruned zones, be sure that no isolated pixels
    # exist between pruned zones (they could not be determined)
    if np.any(labels<0):
        filled = ndimage.binary_propagation(labels>0, mask=labels>=0)
        labels[np.logical_and(np.logical_not(filled), labels == 0)] = -1
        del filled
    labels = np.atleast_3d(labels)
    if np.any(labels < 0):
        lap_sparse = _build_laplacian(data, mask=labels >= 0, beta=beta)
    else:
        lap_sparse = _build_laplacian(data, beta=beta)
    lap_sparse, B = _buildAB(lap_sparse, labels)
    # We solve the linear system
    # lap_sparse X = B
    # where X[i, j] is the probability that a marker of label i arrives
    # first at pixel j by diffusion
    if mode == 'bf':
        lap_sparse = lap_sparse.tocsc()
        solver = sparse.linalg.factorized(lap_sparse.astype(np.double))
        X = np.array([solver(np.array((-B[i, :]).todense()).ravel())\
                for i in range(B.shape[0])])
        X = np.argmax(X, axis=0) + 1
        data = np.squeeze(data)
        return (_clean_labels_ar(X, labels)).reshape(data.shape)
    elif mode == 'amg':
        if not amg_loaded:
            print """the pyamg module (http://code.google.com/p/pyamg/)
            must be installed to use the amg mode"""
            raise ImportError
        lap_sparse = lap_sparse.tocsr()
        le = lap_sparse.shape[0]
        mls = smoothed_aggregation_solver(lap_sparse)
        del lap_sparse
        ll = np.zeros(le, dtype=np.int32)
        proba_max = np.zeros(le, dtype=np.float32)
        for i in range(B.shape[0]):
            x = mls.solve(np.ravel(-B[i, :].todense()).astype(np.float32))
            mask = x > proba_max
            ll[mask] = i
            proba_max[mask] = (x[mask]).astype(np.float32)
            del mask
        del proba_max
        ll = _clean_labels_ar(ll + 1, labels)
        data = np.squeeze(data)
        return ll.reshape(data.shape)

def random_walker_prior(data, prior, mode='bf', gamma=1.e-2):
    """
        Parameters
        ----------

        data : array_like
            Image to be segmented in regions. `data` can be two- or
            three-dimensional.

        prior : array_like
            Array of 1-dimensional probabilities that the pixels
            belong to the different phases. The size of `prior` is n x s
            where n is the number of phases to be segmented, and s the
            total number of pixels.

        mode : {'bf', 'amg'}
            Mode for solving the linear system in the random walker
            algorithm. `mode` can be either 'bf' (for brute force),
            in which case matrices are directly inverted, or 'amg'
            (for algebraic multigrid solver), in which case a multigrid
            approach is used. The 'amg' mode uses the pyamg module
            (http://code.google.com/p/pyamg/), which must be installed
            to use this mode.

        gamma : float
            gamma determines the absence of confidence into the prior.
            The smaller gamma, the more the output values will be determined
            according to the prior only. Conversely, the greater gamma,
            the more continuous the segmented regions will be.

        Returns
        -------

        output : ndarray of ints
            Segmentation of data. The number of phases corresponds to the
            number of lines in prior.

        Notes
        -----

        The algorithm was first proposed in *Multilabel random walker
        image segmentation using prior models*, L. Grady, IEEE CVPR 2005,
        p. 770 (2005).

        Examples
        --------
        >>> a = np.zeros((40, 40))
        >>> a[10:-10, 10:-10] = 1
        >>> a += 0.7*np.random.random((40, 40))
        >>> p = a.max() - a.ravel()
        >>> q = a.ravel()
        >>> prior = np.array([p, q])
        >>> labs = random_walker_prior(a, prior)
    """
    data = np.atleast_3d(data)
    lap_sparse = _build_laplacian(data, beta=50)
    dia = range(data.size)
    shx, shy = lap_sparse.shape
    lap_sparse = lap_sparse + sparse.coo_matrix(
                        (gamma*prior.sum(axis=0), (range(shx), range(shy))))
    del dia
    if mode == 'bf':
        lap_sparse = lap_sparse.tocsc()
        solver = sparse.linalg.factorized(lap_sparse.astype(np.double))
        X = np.array([solver(gamma*label_prior)
                      for label_prior in prior])
    elif mode == 'amg':
        if not amg_loaded:
            print """the pyamg module (http://code.google.com/p/pyamg/)
            must be installed to use the amg mode"""
            raise ImportError
        lap_sparse = lap_sparse.tocsr()
        mls = smoothed_aggregation_solver(lap_sparse)
        del lap_sparse
        X = np.array([mls.solve(gamma*label_prior)
                      for label_prior in prior])
        del mls
    return np.squeeze((np.argmax(X, axis=0)).reshape(data.shape))

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from rest_framework import viewsets, serializers, permissions
from rest_framework import filters
from notification.models import TaskHistory
from logical.models import Database, DatabaseHistory

class TaskSerializer(serializers.ModelSerializer):
    database = serializers.SerializerMethodField('get_database')
    rollback = serializers.SerializerMethodField('had_rollback')
    relevance = serializers.SerializerMethodField('get_relevance')

    class Meta:
        model = TaskHistory
        fields = (
            'id',
            'task_id',
            'task_status',
            'db_id',
            'object_class',
            'object_id',
            'updated_at',
            'user',
            'created_at',
            'task_name',
            'database',
            'rollback',
            'relevance',
        )

    def get_relevance(self, task):
        return task.get_relevance_display()

    def had_rollback(self, task):
        if not task.details:
            return False

        if task.task_name == 'notification.tasks.destroy_database':
            return False

        # TODO: see if do details.lower() is expensive
        return 'rollback step' in task.details.lower()

    def get_database(self, task):
        def make_dict_from_model(instance):
            engine = instance.databaseinfra.engine
            return {
                'name': instance.name,
                'environment': instance.environment.name,
                'engine': '{} {}'.format(
                    engine.engine_type.name,
                    engine.version
                )
            }

        def make_dict_from_history(instance):
            return {
                'name': instance.name,
                'environment': instance.environment,
                'engine': instance.engine
            }

        if task.object_class == Database._meta.db_table:
            try:
                database = (
                    Database.objects
                    .select_related(
                        'environment',
                        'databaseinfra',
                        'databaseinfra__engine',
                        'databaseinfra__engine__enginetype'
                    ).get(id=task.object_id)
                )
            except Database.DoesNotExist:
                try:
                    database_history = DatabaseHistory.objects.get(database_id=task.object_id)
                except DatabaseHistory.DoesNotExist:
                    return None
                else:
                    return make_dict_from_history(database_history)
            else:
                return make_dict_from_model(database)

        return None

class TaskAPI(viewsets.ReadOnlyModelViewSet):

    """
    Task API
    """

    chg_tasks_names = [
        'notification.tasks.destroy_database',
        'notification.tasks.create_database',
        'notification.tasks.destroy_database',
        'notification.tasks.resize_database',
        'notification.tasks.clone_database',
        'notification.tasks.database_disk_resize',
        'notification.tasks.add_instances_to_database',
        'notification.tasks.remove_readonly_instance',
        'database_disk_resize',
        'backup.tasks.restore_snapshot',
        'notification.tasks.upgrade_mongodb_24_to_30',
        'notification.tasks.upgrade_database',
        'notification.tasks.upgrade_database_patch',
        'notification.tasks.reinstall_vm_database',
        'migrate_filer_disk_for_database',
        'maintenance.tasks.node_zone_migrate',
        'maintenance.tasks.database_environment_migrate',
    ]
    model = TaskHistory
    serializer_class = TaskSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
    filter_backends = (filters.OrderingFilter,)
    filter_fields = (
        'task_id',
        'task_status',
        'task_name',
        'object_class',
        'object_id',
        'updated_at',
        'created_at',
        'user',
        'relevance'
    )
    ordering_fields = ('created_at', 'updated_at', 'id')
    ordering = ('-created_at',)
    datetime_fields = ('created_at', 'updated_at')

    def get_queryset(self):
        params = self.request.GET.dict()
        filter_params = {}
        for k, v in params.iteritems():
            if k == 'exclude_system_tasks':
                filter_params['task_name__in'] = self.chg_tasks_names
            elif k.split('__')[0] in self.filter_fields:
                filter_params[k] = v
        return self.model.objects.filter(**filter_params)
<commit_msg>Bugfix - Recreate Slave CHG is not being registered<commit_after># -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from rest_framework import viewsets, serializers, permissions
from rest_framework import filters
from notification.models import TaskHistory
from logical.models import Database, DatabaseHistory

class TaskSerializer(serializers.ModelSerializer):
    database = serializers.SerializerMethodField('get_database')
    rollback = serializers.SerializerMethodField('had_rollback')
    relevance = serializers.SerializerMethodField('get_relevance')

    class Meta:
        model = TaskHistory
        fields = (
            'id',
            'task_id',
            'task_status',
            'db_id',
            'object_class',
            'object_id',
            'updated_at',
            'user',
            'created_at',
            'task_name',
            'database',
            'rollback',
            'relevance',
        )

    def get_relevance(self, task):
        return task.get_relevance_display()

    def had_rollback(self, task):
        if not task.details:
            return False

        if task.task_name == 'notification.tasks.destroy_database':
            return False

        # TODO: see if do details.lower() is expensive
        return 'rollback step' in task.details.lower()

    def get_database(self, task):
        def make_dict_from_model(instance):
            engine = instance.databaseinfra.engine
            return {
                'name': instance.name,
                'environment': instance.environment.name,
                'engine': '{} {}'.format(
                    engine.engine_type.name,
                    engine.version
                )
            }

        def make_dict_from_history(instance):
            return {
                'name': instance.name,
                'environment': instance.environment,
                'engine': instance.engine
            }

        if task.object_class == Database._meta.db_table:
            try:
                database = (
                    Database.objects
                    .select_related(
                        'environment',
                        'databaseinfra',
                        'databaseinfra__engine',
                        'databaseinfra__engine__enginetype'
                    ).get(id=task.object_id)
                )
            except Database.DoesNotExist:
                try:
                    database_history = DatabaseHistory.objects.get(database_id=task.object_id)
                except DatabaseHistory.DoesNotExist:
                    return None
                else:
                    return make_dict_from_history(database_history)
            else:
                return make_dict_from_model(database)

        return None

class TaskAPI(viewsets.ReadOnlyModelViewSet):

    """
    Task API
    """

    chg_tasks_names = [
        'notification.tasks.destroy_database',
        'notification.tasks.create_database',
        'notification.tasks.destroy_database',
        'notification.tasks.resize_database',
        'notification.tasks.clone_database',
        'notification.tasks.database_disk_resize',
        'notification.tasks.add_instances_to_database',
        'notification.tasks.remove_readonly_instance',
        'database_disk_resize',
        'backup.tasks.restore_snapshot',
        'notification.tasks.upgrade_mongodb_24_to_30',
        'notification.tasks.upgrade_database',
        'notification.tasks.upgrade_database_patch',
        'notification.tasks.reinstall_vm_database',
        'migrate_filer_disk_for_database',
        'maintenance.tasks.node_zone_migrate',
        'maintenance.tasks.database_environment_migrate',
        'maintenance.tasks.recreate_slave',
    ]
    model = TaskHistory
    serializer_class = TaskSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
    filter_backends = (filters.OrderingFilter,)
    filter_fields = (
        'task_id',
        'task_status',
        'task_name',
        'object_class',
        'object_id',
        'updated_at',
        'created_at',
        'user',
        'relevance'
    )
    ordering_fields = ('created_at', 'updated_at', 'id')
    ordering = ('-created_at',)
    datetime_fields = ('created_at', 'updated_at')

    def get_queryset(self):
        params = self.request.GET.dict()
        filter_params = {}
        for k, v in params.iteritems():
            if k == 'exclude_system_tasks':
                filter_params['task_name__in'] = self.chg_tasks_names
            elif k.split('__')[0] in self.filter_fields:
                filter_params[k] = v
        return self.model.objects.filter(**filter_params)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re, pydenticon, core, time, global_variables, requests, cloudinary
from PIL import Image, ImageChops, ImageEnhance, ImageFilter, ImageOps

is_sam_plugin = 1
name = "Images"
keywords = ["identicon", "schedule_h", "wallpaper"]
has_toggle = 0
has_set = 0

DEBUG = 1

def initialize():
    core.log(name, "Startup")
    core.log(name, "Hello World!")

def stop():
    core.log(name, "I'm not even running anymore!")

def get_wallpaper():
    core.log(name, "    Downloading the baseimage.")
    path = "/data/wallpaper_background.png"
    response = requests.get("https://earthview.withgoogle.com/")
    html = response.text
    regex = r"background-image: url\((?P<link>.+)\);"
    m = re.search(regex, html, re.IGNORECASE)
    if m:
        if m.group("link"):
            image_url = m.group("link")
        else:
            image_url = None
    else:
        image_url = None
    core.log(name, "    The URL is {}. Downloading to {}.".format(image_url, global_variables.folder_base + path))

    if image_url:
        f = open(global_variables.folder_base + path, "wb")
        f.write(requests.get(image_url).content)
        f.close()
    else:
        core.log(name, "    Error: Download not completed.")
    core.log(name, "    Download completed to {}.".format(global_variables.folder_base + path))
    return path

def resize(im, size, offset=(0,0)):
    bg = Image.new(im.mode, size)
    if im.size[0] < size[0]:
        factor_width = -1
    else:
        factor_width = 1
    if im.size[1] < size[1]:
        factor_height = -1
    else:
        factor_height = 1
    shift_left = factor_width * (((size[0] - im.size[0]) / 2) - offset[0])
    shift_top = factor_height * (((size[1] - im.size[1]) / 2) - offset[1])
    shift_right = size[0] - (factor_width * shift_left)
    shift_bottom = size[1] - (factor_height * shift_top)
    return im.crop((shift_left, shift_top, shift_right, shift_bottom))

def generate_wallpaper(background_path, mask_path, destination_path="/data/wallpaper.png"):

    core.log(name, "    Creating the final image")

    #generate the background

    core.log(name, "      Creating the background")
    bg_layer = Image.open(global_variables.folder_base + background_path)    #the background in color
    bg_layer = bg_layer.convert("RGBA")
    converter_color = ImageEnhance.Color(bg_layer)
    bg_layer = converter_color.enhance(0.05)
    converter_brightness = ImageEnhance.Brightness(bg_layer)
    bg_layer = converter_brightness.enhance(0.8)
    if DEBUG:
        bg_layer.save(global_variables.folder_base + "/data/bg_layer.png")

    #generate the mask

    core.log(name, "      Creating the mask")
    size = bg_layer.size
    mask_BoW = Image.open(global_variables.folder_base + mask_path)     #"BoW" means black icon on white background.
    mask_WoB = ImageOps.invert(mask_BoW)                                #"WoB" is a white icon on black bg.
    if not mask_BoW.size == size:
        mask_WoB = resize(mask_WoB, size)
        mask_BoW = ImageOps.invert(mask_WoB)
    mask_WoB = mask_WoB.convert("1")
    mask_BoW = mask_BoW.convert("1")
    if DEBUG:
        mask_WoB.save(global_variables.folder_base + "/data/mask_WoB.png")
        mask_BoW.save(global_variables.folder_base + "/data/mask_BoW.png")

    #generate the colored overlay

    core.log(name, "      Creating the colored overlay")
    overlay_layer = Image.open(global_variables.folder_base + background_path)
    overlay_layer.putalpha(mask_WoB)
    if DEBUG:
        overlay_layer.save(global_variables.folder_base + "/data/overlay_layer.png")

    #generate the shadow

    core.log(name, "      Creating the dropshadow")
    shadow_layer =  mask_BoW.convert("RGBA")
    shadow_layer.putalpha(mask_WoB)
    """
    A copy if the mask is pasted ontop of itself with a 2px offset into the 4 diagonal directions each to increase it's size into each direction. (The shadow would otherwise disappear behind the colored overlay.)
    The whole layer is then blurred multiple times to increase the blur's effect.
    Finally, the shadow_layer is blended with a completely transparent layer to add some transparency to it.
    """

    offset_layers = []
    offsets = [(1,1),(-1,1),(1,-1),(-1,-1)]     #offset is defined in the definition of the function. Default is 2.
    for (x, y) in offsets:
        offset_layers.append(ImageChops.offset(shadow_layer, x, y))
    for offset_layer in offset_layers:
        shadow_layer.paste(offset_layer, None, offset_layer)

    core.log(name, "      Blurring the shadow")
    for n in range(3):      #as noted above, the Blur is applied multiple times for a stronger effect. 3 has proven as a good compromise between a good effect and not too much necessary calculation.
        core.log(name, "        Step {}/{}".format(n + 1, 3))
        shadow_layer = shadow_layer.filter(ImageFilter.BLUR)
    core.log(name, "      Adding transparency")
    shadow_layer = Image.blend(Image.new("RGBA", size), shadow_layer, 0.8)
    if DEBUG:
        shadow_layer.save(global_variables.folder_base + "/data/shadow_layer.png")

    #merge the shadow with the background

    """
    This will add the shadow manually to the background image. Usign PIL's merge() or composite_alpha() was causing the image underneath the shadow to turn greyish which looked pretty ugly on dark parts of the image.
    To prevent this behaviour, this tool iterates over the pixels of the whole image and changes the colorvalues according to the alphavalue of the corresponding image in the mask.
    If the pixel in the mask is completely transparent (a_mask == 0) the calculation will be skipped and the original pixel won't be changed. If the pixel in the mask is completely opaque (a_mask == 255) the pixel in the original image will be turned black. For every other alpha value the new color is calculated via new = old * (1 - (a_mask / 255)).
    """
    core.log(name, "      Merging the shadow with the background")
    try:
        pixels_changed_count = 0
        pixels_bg = bg_layer.load()
        pixels_mask = shadow_layer.load()
        for x in range(bg_layer.size[0]):
            for y in range(bg_layer.size[1]):
                r_mask, g_mask, b_mask, a_mask = pixels_mask[x, y]
                if 0 < a_mask < 255:
                    r_bg, g_bg, b_bg, a_bg = pixels_bg[x, y]
                    factor = (1.0 - (float(a_mask) / 255.0))
                    r_bg = int(float(r_bg) * factor)
                    g_bg = int(float(g_bg) * factor)
                    b_bg = int(float(b_bg) * factor)
                    pixels_bg[x, y] = (r_bg, g_bg, b_bg, a_bg)
                    pixels_changed_count += 1
                elif a_mask == 255:
                    a_bg = pixels_bg[x, y][-1]
                    pixels_bg[x, y] = (0, 0, 0, a_bg)
                    pixels_changed_count += 1
    except Exception as e:
        core.log(name, "Error: {}".format(e))
    finally:
        core.log(name, "      {} out of {} pixels processed.".format(pixels_changed_count, bg_layer.size[0] * bg_layer.size[1]))
    if DEBUG:
        bg_layer.save(global_variables.folder_base + "/data/bg_layer_shadow.png")
    '''
    #generate the light frame
    frame_layer = overlay_layer.filter(ImageFilter.FIND_EDGES)
    frame_layer.save("./frame_layer.png")
    '''
    #merge the layers

    core.log(name, "      Merging the layers")
    final = Image.new("RGBA", size)
    final.paste(bg_layer)
    #final.paste(shadow_layer, None, shadow_layer)
    final.paste(overlay_layer, None, overlay_layer)
    final.save(global_variables.folder_base + destination_path)
    core.log(name, "    Created the wallpaper at {}.".format(global_variables.folder_base + destination_path))
    return destination_path

def generate_identicon(data="I'm Samantha", path="/data/identicon.png"):
    """
    generates an identicon and sends it to the G2
    possibly via an AutoRemote Plugin?
    """
    core.log(name, "    Generating the Identicon.")
    generator = pydenticon.Generator(5, 5)
    identicon = generator.generate(data, 300, 300)
    core.log(name, "    Generated the Identicon. Saving at {}.".format(global_variables.folder_base + path))
    f = open(global_variables.folder_base + path, "wb")
    f.write(identicon)
    f.close()
    core.log(name, "    Generated the Identicon at {}.".format(global_variables.folder_base + path))
    return path

def process(key, param, comm):
    if key == "schedule_h":
        if param == "0":
            core.log(name, "  Generating the daily wallpaper.")
            wallpaper_bg = get_wallpaper()
            identicon = generate_identicon(str(time.time()))
            wallpaper = generate_wallpaper(wallpaper_bg, identicon)
        else:
            core.log(name, "  Error: illegal parameter: {}.".format(param))
    elif key == "wallpaper":
        core.log(name, "  Generating a new wallpaper.")
        wallpaper_bg = get_wallpaper()
        identicon = generate_identicon(str(time.time()))
        try:
            wallpaper = generate_wallpaper(wallpaper_bg, identicon)
        except Exception as e:
            core.log(name, "Error: {}".format(e))
    elif key == "identicon":
        core.log(name, "  Generating an Identicon with the data '{}'.".format(param))
        if param:
            generate_identicon(param)
        else:
            generate_identicon()
    else:
        core.log(name, "  Error: illegal command: {}.".format(key))<commit_msg>put the whole process()-function into a try/except block, changed handling of illegal parameters a bit<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re, pydenticon, core, time, global_variables, requests, cloudinary
from PIL import Image, ImageChops, ImageEnhance, ImageFilter, ImageOps

is_sam_plugin = 1
name = "Images"
keywords = ["identicon", "schedule_h", "wallpaper"]
has_toggle = 0
has_set = 0

DEBUG = 1

def initialize():
    core.log(name, "Startup")
    core.log(name, "Hello World!")

def stop():
    core.log(name, "I'm not even running anymore!")

def get_wallpaper():
    core.log(name, "    Downloading the baseimage.")
    path = "/data/wallpaper_background.png"
    response = requests.get("https://earthview.withgoogle.com/")
    html = response.text
    regex = r"background-image: url\((?P<link>.+)\);"
    m = re.search(regex, html, re.IGNORECASE)
    if m:
        if m.group("link"):
            image_url = m.group("link")
        else:
            image_url = None
    else:
        image_url = None
    core.log(name, "    The URL is {}. Downloading to {}.".format(image_url, global_variables.folder_base + path))

    if image_url:
        f = open(global_variables.folder_base + path, "wb")
        f.write(requests.get(image_url).content)
        f.close()
    else:
        core.log(name, "    Error: Download not completed.")
    core.log(name, "    Download completed to {}.".format(global_variables.folder_base + path))
    return path

def resize(im, size, offset=(0,0)):
    bg = Image.new(im.mode, size)
    if im.size[0] < size[0]:
        factor_width = -1
    else:
        factor_width = 1
    if im.size[1] < size[1]:
        factor_height = -1
    else:
        factor_height = 1
    shift_left = factor_width * (((size[0] - im.size[0]) / 2) - offset[0])
    shift_top = factor_height * (((size[1] - im.size[1]) / 2) - offset[1])
    shift_right = size[0] - (factor_width * shift_left)
    shift_bottom = size[1] - (factor_height * shift_top)
    return im.crop((shift_left, shift_top, shift_right, shift_bottom))

def generate_wallpaper(background_path, mask_path, destination_path="/data/wallpaper.png"):

    core.log(name, "    Creating the final image")

    #generate the background

    core.log(name, "      Creating the background")
    bg_layer = Image.open(global_variables.folder_base + background_path)    #the background in color
    bg_layer = bg_layer.convert("RGBA")
    converter_color = ImageEnhance.Color(bg_layer)
    bg_layer = converter_color.enhance(0.05)
    converter_brightness = ImageEnhance.Brightness(bg_layer)
    bg_layer = converter_brightness.enhance(0.8)
    if DEBUG:
        bg_layer.save(global_variables.folder_base + "/data/bg_layer.png")

    #generate the mask

    core.log(name, "      Creating the mask")
    size = bg_layer.size
    mask_BoW = Image.open(global_variables.folder_base + mask_path)     #"BoW" means black icon on white background.
    mask_WoB = ImageOps.invert(mask_BoW)                                #"WoB" is a white icon on black bg.
    if not mask_BoW.size == size:
        mask_WoB = resize(mask_WoB, size)
        mask_BoW = ImageOps.invert(mask_WoB)
    mask_WoB = mask_WoB.convert("1")
    mask_BoW = mask_BoW.convert("1")
    if DEBUG:
        mask_WoB.save(global_variables.folder_base + "/data/mask_WoB.png")
        mask_BoW.save(global_variables.folder_base + "/data/mask_BoW.png")

    #generate the colored overlay

    core.log(name, "      Creating the colored overlay")
    overlay_layer = Image.open(global_variables.folder_base + background_path)
    overlay_layer.putalpha(mask_WoB)
    if DEBUG:
        overlay_layer.save(global_variables.folder_base + "/data/overlay_layer.png")

    #generate the shadow

    core.log(name, "      Creating the dropshadow")
    shadow_layer =  mask_BoW.convert("RGBA")
    shadow_layer.putalpha(mask_WoB)
    """
    A copy if the mask is pasted ontop of itself with a 2px offset into the 4 diagonal directions each to increase it's size into each direction. (The shadow would otherwise disappear behind the colored overlay.)
    The whole layer is then blurred multiple times to increase the blur's effect.
    Finally, the shadow_layer is blended with a completely transparent layer to add some transparency to it.
    """

    offset_layers = []
    offsets = [(1,1),(-1,1),(1,-1),(-1,-1)]     #offset is defined in the definition of the function. Default is 2.
    for (x, y) in offsets:
        offset_layers.append(ImageChops.offset(shadow_layer, x, y))
    for offset_layer in offset_layers:
        shadow_layer.paste(offset_layer, None, offset_layer)

    core.log(name, "      Blurring the shadow")
    for n in range(3):      #as noted above, the Blur is applied multiple times for a stronger effect. 3 has proven as a good compromise between a good effect and not too much necessary calculation.
        core.log(name, "        Step {}/{}".format(n + 1, 3))
        shadow_layer = shadow_layer.filter(ImageFilter.BLUR)
    core.log(name, "      Adding transparency")
    shadow_layer = Image.blend(Image.new("RGBA", size), shadow_layer, 0.8)
    if DEBUG:
        shadow_layer.save(global_variables.folder_base + "/data/shadow_layer.png")

    #merge the shadow with the background

    """
    This will add the shadow manually to the background image. Usign PIL's merge() or composite_alpha() was causing the image underneath the shadow to turn greyish which looked pretty ugly on dark parts of the image.
    To prevent this behaviour, this tool iterates over the pixels of the whole image and changes the colorvalues according to the alphavalue of the corresponding image in the mask.
    If the pixel in the mask is completely transparent (a_mask == 0) the calculation will be skipped and the original pixel won't be changed. If the pixel in the mask is completely opaque (a_mask == 255) the pixel in the original image will be turned black. For every other alpha value the new color is calculated via new = old * (1 - (a_mask / 255)).
    """
    core.log(name, "      Merging the shadow with the background")
    try:
        pixels_changed_count = 0
        pixels_bg = bg_layer.load()
        pixels_mask = shadow_layer.load()
        for x in range(bg_layer.size[0]):
            for y in range(bg_layer.size[1]):
                r_mask, g_mask, b_mask, a_mask = pixels_mask[x, y]
                if 0 < a_mask < 255:
                    r_bg, g_bg, b_bg, a_bg = pixels_bg[x, y]
                    factor = (1.0 - (float(a_mask) / 255.0))
                    r_bg = int(float(r_bg) * factor)
                    g_bg = int(float(g_bg) * factor)
                    b_bg = int(float(b_bg) * factor)
                    pixels_bg[x, y] = (r_bg, g_bg, b_bg, a_bg)
                    pixels_changed_count += 1
                elif a_mask == 255:
                    a_bg = pixels_bg[x, y][-1]
                    pixels_bg[x, y] = (0, 0, 0, a_bg)
                    pixels_changed_count += 1
    except Exception as e:
        core.log(name, "Error: {}".format(e))
    finally:
        core.log(name, "      {} out of {} pixels processed.".format(pixels_changed_count, bg_layer.size[0] * bg_layer.size[1]))
    if DEBUG:
        bg_layer.save(global_variables.folder_base + "/data/bg_layer_shadow.png")
    '''
    #generate the light frame
    frame_layer = overlay_layer.filter(ImageFilter.FIND_EDGES)
    frame_layer.save("./frame_layer.png")
    '''
    #merge the layers

    core.log(name, "      Merging the layers")
    final = Image.new("RGBA", size)
    final.paste(bg_layer)
    #final.paste(shadow_layer, None, shadow_layer)
    final.paste(overlay_layer, None, overlay_layer)
    final.save(global_variables.folder_base + destination_path)
    core.log(name, "    Created the wallpaper at {}.".format(global_variables.folder_base + destination_path))
    return destination_path

def generate_identicon(data="I'm Samantha", path="/data/identicon.png"):
    """
    generates an identicon and sends it to the G2
    possibly via an AutoRemote Plugin?
    """
    core.log(name, "    Generating the Identicon.")
    generator = pydenticon.Generator(5, 5)
    identicon = generator.generate(data, 300, 300)
    core.log(name, "    Generated the Identicon. Saving at {}.".format(global_variables.folder_base + path))
    f = open(global_variables.folder_base + path, "wb")
    f.write(identicon)
    f.close()
    core.log(name, "    Generated the Identicon at {}.".format(global_variables.folder_base + path))
    return path

def process(key, param, comm):
    try:
        if key == "schedule_h":
            if param == "0":
                core.log(name, "  Generating the daily wallpaper.")
                wallpaper_bg = get_wallpaper()
                identicon = generate_identicon(str(time.time()))
                wallpaper = generate_wallpaper(wallpaper_bg, identicon)
            else:
                core.log(name, "  Warning: parameter {} not in use.".format(param))
        elif key == "wallpaper":
            core.log(name, "  Generating a new wallpaper.")
            wallpaper_bg = get_wallpaper()
            identicon = generate_identicon(str(time.time()))
            wallpaper = generate_wallpaper(wallpaper_bg, identicon)
        elif key == "identicon":
            core.log(name, "  Generating an Identicon with the data '{}'.".format(param))
            if param:
                generate_identicon(param)
            else:
                generate_identicon()
        else:
            core.log(name, "  Warning: parameter {} not in use.".format(param))
    except Exception as e:
        core.log(name, "Error: {}".format(e))<|endoftext|>


<commit_before>import pytest
from controllers.base.models import publish_to_websocket
from controllers.base.tests.base import ControllerBaseTestCase
from controllers.freebasics.forms import FreeBasicsControllerForm, DEFAULT_PORT, \
    TEMPLATE_CHOICES
from controllers.freebasics.models import FreeBasicsController
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.http import QueryDict

@pytest.mark.django_db
class FreeBasicsControllerFormTestCase(ControllerBaseTestCase):
    fixtures = ['test_users.json', 'test_social_auth.json']

    def setUp(self):
        self.user = User.objects.get(username='testuser')
        post_save.disconnect(publish_to_websocket, sender=FreeBasicsController)
        self.maxDiff = None

    def test__process_data_empty(self):
        form = FreeBasicsControllerForm()
        self.assertIsNone(form._process_data(None))

    def test__process_data(self):
        data = QueryDict(mutable=True)
        data.appendlist('name', 'Test App')
        data.appendlist('selected_template', 'option1')
        form = FreeBasicsControllerForm()
        self.assertIsNotNone(form._process_data(data))

    def test__process_data_error(self):
        data = QueryDict(mutable=True)
        data.appendlist('name', 'Test App')
        data.appendlist('selected_template', 'optio')
        form = FreeBasicsControllerForm()
        self.assertRaises(KeyError, form._process_data, data)

    def test__get_docker_image_name(self):
        for t in TEMPLATE_CHOICES:
            controller = FreeBasicsController.objects.create(
                name='Test App',
                owner=self.user,
                selected_template=t[0],
            )
            controller.save()
            form = FreeBasicsControllerForm(instance=controller)
            self.assertEqual(form._get_docker_image_name(t[0]),
                             "universalcore/" + dict(TEMPLATE_CHOICES)[t[0]])

    def test__get_marathon_cmd(self):
        for t in TEMPLATE_CHOICES:
            controller = FreeBasicsController.objects.create(
                name='Test App',
                owner=self.user,
                selected_template=t[0],
            )
            controller.save()
            form = FreeBasicsControllerForm(instance=controller)
            self.assertRegexpMatches(
                form._get_marathon_cmd(t[0]),
                "./deploy/docker-entrypoint.sh [A-Za-z]+ [A-Za-z]+\.wsgi 8000")
<commit_msg>fix: unused import<commit_after>import pytest
from controllers.base.models import publish_to_websocket
from controllers.base.tests.base import ControllerBaseTestCase
from controllers.freebasics.forms import FreeBasicsControllerForm, \
    TEMPLATE_CHOICES
from controllers.freebasics.models import FreeBasicsController
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.http import QueryDict

@pytest.mark.django_db
class FreeBasicsControllerFormTestCase(ControllerBaseTestCase):
    fixtures = ['test_users.json', 'test_social_auth.json']

    def setUp(self):
        self.user = User.objects.get(username='testuser')
        post_save.disconnect(publish_to_websocket, sender=FreeBasicsController)
        self.maxDiff = None

    def test__process_data_empty(self):
        form = FreeBasicsControllerForm()
        self.assertIsNone(form._process_data(None))

    def test__process_data(self):
        data = QueryDict(mutable=True)
        data.appendlist('name', 'Test App')
        data.appendlist('selected_template', 'option1')
        form = FreeBasicsControllerForm()
        self.assertIsNotNone(form._process_data(data))

    def test__process_data_error(self):
        data = QueryDict(mutable=True)
        data.appendlist('name', 'Test App')
        data.appendlist('selected_template', 'optio')
        form = FreeBasicsControllerForm()
        self.assertRaises(KeyError, form._process_data, data)

    def test__get_docker_image_name(self):
        for t in TEMPLATE_CHOICES:
            controller = FreeBasicsController.objects.create(
                name='Test App',
                owner=self.user,
                selected_template=t[0],
            )
            controller.save()
            form = FreeBasicsControllerForm(instance=controller)
            self.assertEqual(form._get_docker_image_name(t[0]),
                             "universalcore/" + dict(TEMPLATE_CHOICES)[t[0]])

    def test__get_marathon_cmd(self):
        for t in TEMPLATE_CHOICES:
            controller = FreeBasicsController.objects.create(
                name='Test App',
                owner=self.user,
                selected_template=t[0],
            )
            controller.save()
            form = FreeBasicsControllerForm(instance=controller)
            self.assertRegexpMatches(
                form._get_marathon_cmd(t[0]),
                "./deploy/docker-entrypoint.sh [A-Za-z]+ [A-Za-z]+\.wsgi 8000")
<|endoftext|>


<commit_before>from rest_framework import serializers
from .models import APIRequest
from robocrm.models import RoboUser
from projects.models import Project
from officers.models import Officer
from webcams.models import Webcam
from sponsors.models import Sponsor
from social_media.models import SocialMedia
from channels.models import Channel
from faq.models import Category, QA
from tshirts.models import TShirt
from posters.models import Poster
from easy_thumbnails.templatetags.thumbnail import thumbnail_url
from django.contrib.contenttypes.models import ContentType

class BalanceSerializer(serializers.Serializer):
    """
    To validate /users/:id/balance/ endpoint.
    """

    amount = serializers.DecimalField(max_digits=5, decimal_places=2)
    meta = serializers.CharField(required=False, allow_blank=True)

class EmailSerializer(serializers.Serializer):
    """
    To validate /users/:id/email/ endpoint.
    """

    subject = serializers.CharField()
    content = serializers.CharField()
    meta = serializers.CharField(required=False, allow_blank=True)

class RFIDSerializer(serializers.Serializer):
    """
    To validate /rfid/ and /users/:id/rfid/ lookup endpoint.
    """

    rfid = serializers.CharField()
    meta = serializers.CharField(required=False, allow_blank=True)

    def validate_rfid(self, value):
        """
        Ensures the RFID is the proper length
        """

        if len(value) != 8:
            raise serializers.ValidationError("RFIDs must be 8 characters long")

        return value

class MagneticSerializer(serializers.Serializer):
    """
    To validate /magnetic/ lookup endpoint.
    """

    magnetic = serializers.CharField()
    meta = serializers.CharField(required=False, allow_blank=True)

    def validate_magnetic(self, value):
        """
        Ensures the Magnetic ID is the proper length
        """

        if len(value) != 9:
            raise serializers.ValidationError("Magnetic IDs must be 9 characters long")

        return value

class APIRequestSerializer(serializers.ModelSerializer):

    class Meta:
        model = APIRequest
        fields = ('id', 'endpoint', 'extra', 'user', 'updater_is_project', 'updater_id', 'created_datetime', 'updated_datetime', 'success', 'meta', )

class WebcamSerializer(serializers.ModelSerializer):

    class Meta:
        model = Webcam
        fields = ('id', 'name', 'url', )

class RoboUserSerializer(serializers.ModelSerializer):

    username = serializers.CharField(source='user.username', read_only=True)
    first_name = serializers.CharField(source='user.first_name', read_only=True)
    last_name = serializers.CharField(source='user.last_name', read_only=True)
    date_joined = serializers.DateTimeField(source='user.date_joined', read_only=True)
    last_login = serializers.DateTimeField(source='user.last_login', read_only=True)

    magnetic = serializers.BooleanField(source='is_magnetic_set', read_only=True)
    rfid = serializers.BooleanField(source='is_rfid_set', read_only=True)
    machines = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = RoboUser
        fields = ('id', 'username', 'first_name', 'last_name', 'date_joined', 'last_login', 'magnetic', 'rfid', 'balance', 'machines', )

class ProjectSerializer(serializers.ModelSerializer):

    class Meta:
        model = Project
        fields = ('id', 'name', 'image', 'blurb', 'description', 'website', 'display', 'leaders', 'last_api_activity', )

class OfficerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Officer
        fields = ('id', 'position', 'user', 'image', 'description', 'order', )

class ChannelSerializer(serializers.ModelSerializer):
    name = serializers.CharField(read_only=True)
    created = serializers.DateTimeField(source='created_datetime', read_only=True)
    updated = serializers.DateTimeField(source='updated_datetime', read_only=True)
    description = serializers.CharField(read_only=True)

    # TODO: bring this functionality to all ModelSerializers
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if hasattr(kwargs, 'context'):
            request = kwargs['context']['request']
            params = request.QUERY_PARAMS
            fields = params.get('fields')
            exclude = params.get('exclude')

            if fields is not None:
                if "," in fields:
                    fields = fields.split(',')
                else:
                    fields = [fields]

                allowed = set(fields)
                existing = set(self.fields.keys())
                for field_name in existing - allowed:
                    if field_name in self.fields:
                        self.fields.pop(field_name)

            if exclude is not None:
                if "," in exclude:
                    exclude = exclude.split(',')
                else:
                    exclude = [exclude]

                disallowed = set(exclude)
                existing = set(self.fields.keys())
                for field_name in disallowed:
                    if field_name in self.fields:
                        self.fields.pop(field_name)

    def update(self, instance, validated_data):
        user = self.context['request'].user
        instance.updater_object = user
        return super().update(instance, validated_data)

    class Meta:
        model = Channel
        fields = ('id', 'name', 'value', 'created', 'updated', 'description', )

class SponsorSerializer(serializers.ModelSerializer):

    class Meta:
        model = Sponsor
        fields = ('id', 'name', 'logo', 'website', 'active', 'order', )

class SocialMediaSerializer(serializers.ModelSerializer):

    class Meta:
        model = SocialMedia
        fields = ('id', 'name', 'url', 'order', )

class QASerializer(serializers.ModelSerializer):

    class Meta:
        model = QA
        fields = ('id', 'question', 'answer', )

class CategorySerializer(serializers.ModelSerializer):
    qas = QASerializer(source='qa_set', many=True)

    class Meta:
        model = Category
        depth = 2
        fields = ('id', 'title', 'qas')

class TShirtSerializer(serializers.ModelSerializer):
    class Meta:
        model = TShirt
        fields = ('id', 'name', 'year', 'front_image', 'back_image', )

class PosterSerializer(serializers.ModelSerializer):

    image_thumb = serializers.SerializerMethodField('image_thumb_url')

    class Meta:
        model = Poster
        fields = ('id', 'name', 'year', 'image_thumb', 'image', )

    def image_thumb_url(self, obj):
        url = thumbnail_url(obj.image, 'poster_index')
        return self.context['request'].build_absolute_uri(url)

# TODO: move to machines app
from robocrm.models import Machine

class MachineSerializer(serializers.ModelSerializer):

    class Meta:
        model = Machine
        fields = ('id', 'type', )
<commit_msg>Updated API Magnetic and RFID serializers.<commit_after>from rest_framework import serializers
from .models import APIRequest
from robocrm.models import RoboUser
from projects.models import Project
from officers.models import Officer
from webcams.models import Webcam
from sponsors.models import Sponsor
from social_media.models import SocialMedia
from channels.models import Channel
from faq.models import Category, QA
from tshirts.models import TShirt
from posters.models import Poster
from easy_thumbnails.templatetags.thumbnail import thumbnail_url
from django.contrib.contenttypes.models import ContentType

class BalanceSerializer(serializers.Serializer):
    """
    To validate /users/:id/balance/ endpoint.
    """

    amount = serializers.DecimalField(max_digits=5, decimal_places=2)
    meta = serializers.CharField(required=False, allow_blank=True)

class EmailSerializer(serializers.Serializer):
    """
    To validate /users/:id/email/ endpoint.
    """

    subject = serializers.CharField()
    content = serializers.CharField()
    meta = serializers.CharField(required=False, allow_blank=True)

class RFIDSerializer(serializers.Serializer):
    """
    To validate /rfid/ and /users/:id/rfid/ lookup endpoint.
    """

    rfid = serializers.RegexField('^[A-F0-9]{8}$')
    meta = serializers.CharField(required=False, allow_blank=True)

class MagneticSerializer(serializers.Serializer):
    """
    To validate /magnetic/ lookup endpoint.
    """

    magnetic = serializers.RegexField('^[0-9]{9}$')
    meta = serializers.CharField(required=False, allow_blank=True)

class APIRequestSerializer(serializers.ModelSerializer):

    class Meta:
        model = APIRequest
        fields = ('id', 'endpoint', 'extra', 'user', 'updater_is_project', 'updater_id', 'created_datetime', 'updated_datetime', 'success', 'meta', )

class WebcamSerializer(serializers.ModelSerializer):

    class Meta:
        model = Webcam
        fields = ('id', 'name', 'url', )

class RoboUserSerializer(serializers.ModelSerializer):

    username = serializers.CharField(source='user.username', read_only=True)
    first_name = serializers.CharField(source='user.first_name', read_only=True)
    last_name = serializers.CharField(source='user.last_name', read_only=True)
    date_joined = serializers.DateTimeField(source='user.date_joined', read_only=True)
    last_login = serializers.DateTimeField(source='user.last_login', read_only=True)

    magnetic = serializers.BooleanField(source='is_magnetic_set', read_only=True)
    rfid = serializers.BooleanField(source='is_rfid_set', read_only=True)
    machines = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = RoboUser
        fields = ('id', 'username', 'first_name', 'last_name', 'date_joined', 'last_login', 'magnetic', 'rfid', 'balance', 'machines', )

class ProjectSerializer(serializers.ModelSerializer):

    class Meta:
        model = Project
        fields = ('id', 'name', 'image', 'blurb', 'description', 'website', 'display', 'leaders', 'last_api_activity', )

class OfficerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Officer
        fields = ('id', 'position', 'user', 'image', 'description', 'order', )

class ChannelSerializer(serializers.ModelSerializer):
    name = serializers.CharField(read_only=True)
    created = serializers.DateTimeField(source='created_datetime', read_only=True)
    updated = serializers.DateTimeField(source='updated_datetime', read_only=True)
    description = serializers.CharField(read_only=True)

    # TODO: bring this functionality to all ModelSerializers
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if hasattr(kwargs, 'context'):
            request = kwargs['context']['request']
            params = request.QUERY_PARAMS
            fields = params.get('fields')
            exclude = params.get('exclude')

            if fields is not None:
                if "," in fields:
                    fields = fields.split(',')
                else:
                    fields = [fields]

                allowed = set(fields)
                existing = set(self.fields.keys())
                for field_name in existing - allowed:
                    if field_name in self.fields:
                        self.fields.pop(field_name)

            if exclude is not None:
                if "," in exclude:
                    exclude = exclude.split(',')
                else:
                    exclude = [exclude]

                disallowed = set(exclude)
                existing = set(self.fields.keys())
                for field_name in disallowed:
                    if field_name in self.fields:
                        self.fields.pop(field_name)

    def update(self, instance, validated_data):
        user = self.context['request'].user
        instance.updater_object = user
        return super().update(instance, validated_data)

    class Meta:
        model = Channel
        fields = ('id', 'name', 'value', 'created', 'updated', 'description', )

class SponsorSerializer(serializers.ModelSerializer):

    class Meta:
        model = Sponsor
        fields = ('id', 'name', 'logo', 'website', 'active', 'order', )

class SocialMediaSerializer(serializers.ModelSerializer):

    class Meta:
        model = SocialMedia
        fields = ('id', 'name', 'url', 'order', )

class QASerializer(serializers.ModelSerializer):

    class Meta:
        model = QA
        fields = ('id', 'question', 'answer', )

class CategorySerializer(serializers.ModelSerializer):
    qas = QASerializer(source='qa_set', many=True)

    class Meta:
        model = Category
        depth = 2
        fields = ('id', 'title', 'qas')

class TShirtSerializer(serializers.ModelSerializer):
    class Meta:
        model = TShirt
        fields = ('id', 'name', 'year', 'front_image', 'back_image', )

class PosterSerializer(serializers.ModelSerializer):

    image_thumb = serializers.SerializerMethodField('image_thumb_url')

    class Meta:
        model = Poster
        fields = ('id', 'name', 'year', 'image_thumb', 'image', )

    def image_thumb_url(self, obj):
        url = thumbnail_url(obj.image, 'poster_index')
        return self.context['request'].build_absolute_uri(url)

# TODO: move to machines app
from robocrm.models import Machine

class MachineSerializer(serializers.ModelSerializer):

    class Meta:
        model = Machine
        fields = ('id', 'type', )
<|endoftext|>