<commit_before>import numpy as np
from scipy.ndimage.filters import maximum_filter, minimum_filter, convolve

from ..transform import integral_image
from ..feature.corner import _compute_auto_correlation
from ..morphology import convex_hull_image
from ..util import img_as_float

from .censure_cy import _censure_dob_loop

def _get_filtered_image(image, n, mode='DoB'):
    # TODO : Implement the STAR and Octagon mode
    if mode == 'DoB':
        inner_wt = (1.0 / (2 * n + 1)**2)
        outer_wt = (1.0 / (12 * n**2 + 4 * n))
        integral_img = integral_image(image)
        filtered_image = np.zeros(image.shape)
        _censure_dob_loop(image, n, integral_img, filtered_image, inner_wt, outer_wt)

        return filtered_image

def _oct(m, n):
    f = np.zeros((m + 2*n, m + 2*n))
    f[0, n] = 1
    f[n, 0] = 1
    f[0, m + n -1] = 1
    f[m + n - 1, 0] = 1
    f[-1, n] = 1
    f[n, -1] = 1
    f[-1, m + n - 1] = 1
    f[m + n - 1, -1] = 1
    return convex_hull_image(f).astype(int)

def _octagon_filter(mo, no, mi, ni):
    outer = (mo + 2 * no)**2 - 2 * no * (no + 1)
    inner = (mi + 2 * ni)**2 - 2 * ni * (ni + 1)
    outer_wt = 1.0 / (outer - inner)
    inner_wt = 1.0 / inner
    c = ((mo + 2 * no) - (mi + 2 * ni)) / 2
    outer_oct = _oct(mo, no)
    inner_oct = np.zeros((mo + 2 * no, mo + 2 * no))
    inner_oct[c:-c, c:-c] = _oct(mi, ni)
    bfilter = outer_wt * outer_oct - (outer_wt + inner_wt) * inner_oct
    return bfilter

"""
def _filter_using_convolve(image, n, mode='DoB'):

    if mode == 'DoB':
        inner_wt = (1.0 / (2*n + 1)**2)
        outer_wt = (1.0 / (12*n**2 + 4*n))
        dob_filter = np.zeros((4 * n + 1, 4 * n + 1))
        dob_filter[:] = outer_wt
        dob_filter[n : 3 * n + 1, n : 3 * n + 1] = - inner_wt
        return convolve(image, dob_filter)

    elif mode == 'Octagon':
        outer_shape = [(5, 2), (5, 3), (7, 3), (9, 4), (9, 7), (13, 7), (15, 10)]
        inner_shape = [(3, 0), (3, 1), (3, 2), (5, 2), (5, 3), (5, 4), (5, 5)]
        return convolve(image, _octagon_filter(outer_shape[n - 1][0], outer_shape[n - 1][1], inner_shape[n - 1][0], inner_shape[n - 1][1]))
"""

def _suppress_line(response, sigma, rpc_threshold):
    Axx, Axy, Ayy = _compute_auto_correlation(response, sigma)
    detA = Axx * Ayy - Axy**2
    traceA = Axx + Ayy
    # ratio of principal curvatures
    rpc = traceA / (detA + 0.001)
    response[rpc > rpc_threshold] = 0
    return response

def censure_keypoints(image, mode='DoB', no_of_scales=7, threshold=0.03, rpc_threshold=10):
    # TODO : Decide number of scales. Image-size dependent?
    image = np.squeeze(image)
    if image.ndim != 2:
        raise ValueError("Only 2-D gray-scale images supported.")
    image = img_as_float(image)

    image = np.ascontiguousarray(image)

    # Generating all the scales
    scales = np.zeros((image.shape[0], image.shape[1], no_of_scales))
    for i in xrange(no_of_scales):
        scales[:, :, i] = _get_filtered_image(image, i + 1, mode)

    # Suppressing points that are neither minima or maxima in their 3 x 3 x 3
    # neighbourhood to zero
    minimas = (minimum_filter(scales, (3, 3, 3)) == scales).astype(int) * scales
    maximas = (maximum_filter(scales, (3, 3, 3)) == scales).astype(int) * scales
    # Suppressing minimas and maximas weaker than threshold
    minimas[np.abs(minimas) < threshold] = 0
    maximas[np.abs(maximas) < threshold] = 0
    response = maximas + minimas

    for i in xrange(1, no_of_scales - 1):
        response[:, :, i] = _suppress_line(response[:, :, i], (1 + i / 3.0), rpc_threshold)

    # Returning keypoints with its scale
    keypoints = np.transpose(np.nonzero(response[:, :, 1:no_of_scales])) + [0, 0, 1]
    return keypoints
<commit_msg>Correcting the definition of Ratio of Principal Curvatures<commit_after>import numpy as np
from scipy.ndimage.filters import maximum_filter, minimum_filter, convolve

from ..transform import integral_image
from ..feature.corner import _compute_auto_correlation
from ..morphology import convex_hull_image
from ..util import img_as_float

from .censure_cy import _censure_dob_loop

def _get_filtered_image(image, n, mode='DoB'):
    # TODO : Implement the STAR and Octagon mode
    if mode == 'DoB':
        inner_wt = (1.0 / (2 * n + 1)**2)
        outer_wt = (1.0 / (12 * n**2 + 4 * n))
        integral_img = integral_image(image)
        filtered_image = np.zeros(image.shape)
        _censure_dob_loop(image, n, integral_img, filtered_image, inner_wt, outer_wt)

        return filtered_image

def _oct(m, n):
    f = np.zeros((m + 2*n, m + 2*n))
    f[0, n] = 1
    f[n, 0] = 1
    f[0, m + n -1] = 1
    f[m + n - 1, 0] = 1
    f[-1, n] = 1
    f[n, -1] = 1
    f[-1, m + n - 1] = 1
    f[m + n - 1, -1] = 1
    return convex_hull_image(f).astype(int)

def _octagon_filter(mo, no, mi, ni):
    outer = (mo + 2 * no)**2 - 2 * no * (no + 1)
    inner = (mi + 2 * ni)**2 - 2 * ni * (ni + 1)
    outer_wt = 1.0 / (outer - inner)
    inner_wt = 1.0 / inner
    c = ((mo + 2 * no) - (mi + 2 * ni)) / 2
    outer_oct = _oct(mo, no)
    inner_oct = np.zeros((mo + 2 * no, mo + 2 * no))
    inner_oct[c:-c, c:-c] = _oct(mi, ni)
    bfilter = outer_wt * outer_oct - (outer_wt + inner_wt) * inner_oct
    return bfilter

"""
def _filter_using_convolve(image, n, mode='DoB'):

    if mode == 'DoB':
        inner_wt = (1.0 / (2*n + 1)**2)
        outer_wt = (1.0 / (12*n**2 + 4*n))
        dob_filter = np.zeros((4 * n + 1, 4 * n + 1))
        dob_filter[:] = outer_wt
        dob_filter[n : 3 * n + 1, n : 3 * n + 1] = - inner_wt
        return convolve(image, dob_filter)

    elif mode == 'Octagon':
        outer_shape = [(5, 2), (5, 3), (7, 3), (9, 4), (9, 7), (13, 7), (15, 10)]
        inner_shape = [(3, 0), (3, 1), (3, 2), (5, 2), (5, 3), (5, 4), (5, 5)]
        return convolve(image, _octagon_filter(outer_shape[n - 1][0], outer_shape[n - 1][1], inner_shape[n - 1][0], inner_shape[n - 1][1]))
"""

def _suppress_line(response, sigma, rpc_threshold):
    Axx, Axy, Ayy = _compute_auto_correlation(response, sigma)
    detA = Axx * Ayy - Axy**2
    traceA = Axx + Ayy
    # ratio of principal curvatures
    rpc = traceA**2 / (detA + 0.001)
    response[rpc > rpc_threshold] = 0
    return response

def censure_keypoints(image, mode='DoB', no_of_scales=7, threshold=0.03, rpc_threshold=10):
    # TODO : Decide number of scales. Image-size dependent?
    image = np.squeeze(image)
    if image.ndim != 2:
        raise ValueError("Only 2-D gray-scale images supported.")
    image = img_as_float(image)

    image = np.ascontiguousarray(image)

    # Generating all the scales
    scales = np.zeros((image.shape[0], image.shape[1], no_of_scales))
    for i in xrange(no_of_scales):
        scales[:, :, i] = _get_filtered_image(image, i + 1, mode)

    # Suppressing points that are neither minima or maxima in their 3 x 3 x 3
    # neighbourhood to zero
    minimas = (minimum_filter(scales, (3, 3, 3)) == scales).astype(int) * scales
    maximas = (maximum_filter(scales, (3, 3, 3)) == scales).astype(int) * scales
    # Suppressing minimas and maximas weaker than threshold
    minimas[np.abs(minimas) < threshold] = 0
    maximas[np.abs(maximas) < threshold] = 0
    response = maximas + minimas

    for i in xrange(1, no_of_scales - 1):
        response[:, :, i] = _suppress_line(response[:, :, i], (1 + i / 3.0), rpc_threshold)

    # Returning keypoints with its scale
    keypoints = np.transpose(np.nonzero(response[:, :, 1:no_of_scales])) + [0, 0, 1]
    return keypoints
<|endoftext|>


<commit_before>from skimage._shared.utils import skimage_deprecation
from warnings import warn
warn(skimage_deprecation('The `skimage.filter` module has been renamed to '
                         '`skimage.filters`.  This placeholder module '
                         'will be removed in v0.13.'))
del warn
del skimage_deprecation

from ..filters import *
<commit_msg>For `filter` submodule, explicitly set warning registry location<commit_after>from skimage._shared.utils import skimage_deprecation
from warnings import warn_explicit
__warningregistry__ = {}
warn_explicit(skimage_deprecation('The `skimage.filter` module has been renamed to '
                                  '`skimage.filters`.  This placeholder module '
                                  'will be removed in v0.13.'), category=None,
                                  filename=__file__, lineno=4,
                                  registry=__warningregistry__)
del warn_explicit
del skimage_deprecation

from ..filters import *
<|endoftext|>


<commit_before>import numpy as np

__all__ = ['frangi', 'hessian']

def _frangi_hessian_common_filter(image, scale, scale_step, beta1, beta2,
                                  frangi_=True, black_ridges=True):
    """This is an intermediate function for Frangi and Hessian filters.

    Shares the common code for Frangi and Hessian functions.

    Parameters
    ----------
    image : (N, M) ndarray
        Array with input image data.
    scale : tuple of floats, optional
        The range of sigmas used.
    scale_step : float, optional
        Step size between sigmas.
    beta1 : float, optional
        Frangi correction constant.
    beta2 : float, optional
        Frangi correction constant.
    black_ridges : boolean, optional
        If True (default), detects black ridges, if False - white ones.

    Returns
    -------
    filtered_list : list
        List of pre-filtered images.

    """

    # Import has to be here due to circular import error
    from ..feature import hessian_matrix, hessian_matrix_eigvals

    sigmas = np.arange(scale[0], scale[1], scale_step)

    if np.any(np.asarray(sigmas) < 0.0):
        raise ValueError("Sigma values less than zero are not valid")

    beta1 = 2 * beta1 ** 2
    beta2 = 2 * beta2 ** 2

    filtered_array = np.zeros(np.shape(image),len(sigmas))

    # Filtering for all sigmas
    for sigma in sigmas:
        # Make 2D hessian
        (Dxx, Dxy, Dyy) = hessian_matrix(image, sigma)

        # Correct for scale
        Dxx = (sigma ** 2) * Dxx
        Dxy = (sigma ** 2) * Dxy
        Dyy = (sigma ** 2) * Dyy

        # Calculate (abs sorted) eigenvalues and vectors
        (lambda1, lambda2) = hessian_matrix_eigvals(Dxx, Dxy, Dyy)

        # Compute some similarity measures
        lambda1[lambda1 == 0] = 1e-10
        rb = (lambda2 / lambda1) ** 2
        s2 = lambda1 ** 2 + lambda2 ** 2

        # Compute the output image
        filtered = np.exp(-rb / beta1) * (np.ones(np.shape(image)) -
                                          np.exp(-s2 / beta2))

        # Store the results in 3D matrices
        filtered_array.append([filtered, lambda1])
    return filtered_array

def frangi(image, scale=(1, 10), scale_step=2, beta1=0.5, beta2=15,
           black_ridges=True):
    """Filter an image with the Frangi filter.

    This filter can be used to detect continous edges, e.g. vessels,
    wrinkles, rivers. It can be used to calculate the fraction of the
    whole image containing such objects.

    Calculates the eigenvectors of the Hessian to compute the likeliness of
    an image region to vessels, according to the method described in _[1].

    Parameters
    ----------
    image : (N, M) ndarray
        Array with input image data.
    scale : tuple of floats, optional
        The range of sigmas used.
    scale_step : float, optional
        Step size between sigmas.
    beta1 : float, optional
        Frangi correction constant.
    beta2 : float, optional
        Frangi correction constant.
    black_ridges : boolean, optional
        Detect black ridges (default) set to true, for
        white ridges set to false.

    Returns
    -------
    out : (N, M) ndarray
        Filtered image (maximum of pixels across all scales).

    Notes
    -----
    Written by Marc Schrijver, 2/11/2001
    Re-Written by D. J. Kroon University of Twente (May 2009)

    References
    ----------
    .. [1] A. Frangi, W. Niessen, K. Vincken, and M. Viergever. "Multiscale
    vessel enhancement filtering," In LNCS, vol. 1496, pages 130-137,
    Germany, 1998. Springer-Verlag.
    .. [2] Kroon, D.J.: Hessian based frangi vesselness filter.
    .. [3] http://mplab.ucsd.edu/tutorials/gabor.pdf.
    """

    filtered_array = _frangi_hessian_common_filter(image, scale, scale_step,
                                                   beta1, beta2)

    for i in range(len(filtered_array)):
        filtered = filtered_array[i][0]
        Lambda1 = filtered_array[i][1]
        if black_ridges:
            filtered[Lambda1 < 0] = 0
        else:
            filtered[Lambda1 >= 0] = 0
        filtered_array[i][0] = filtered

    # Return for every pixel the value of the scale(sigma) with the maximum
    # output pixel value

    return np.max(filtered_array, axis=0)[0]

def hessian(image, scale=(1, 10), scale_step=2, beta1=0.5, beta2=15):
    """Filter an image with the Hessian filter.

    This filter can be used to detect continous edges, e.g. vessels,
    wrinkles, rivers. It can be used to calculate the fraction of the whole
    image containing such objects

    Almost equal to frangi filter, but uses alternative method of smoothing.
    Address _[1] to find the differences between Frangi and Hessian filters.

    Parameters
    ----------
    image : (N, M) ndarray
        Array with input image data.
    scale : tuple of floats, optional
        The range of sigmas used.
    scale_step : float, optional
        Step size between sigmas.
    beta1 : float, optional
        Frangi correction constant.
    beta2 : float, optional
        Frangi correction constant.

    Returns
    -------
    out : (N, M) ndarray
        Filtered image (maximum of pixels across all scales).

    Notes
    -----
    Written by Marc Schrijver, 2/11/2001
    Re-Written by D. J. Kroon University of Twente (May 2009)

    References
    ----------
    .. [1] Choon-Ching Ng, Moi Hoon Yap, Nicholas Costen and Baihua Li,
    "Automatic Wrinkle Detection using Hybrid Hessian Filter".
    """

    filtered_array = _frangi_hessian_common_filter(image, scale, scale_step,
                                                   beta1, beta2)

    for i in range(len(filtered_array)):
        filtered = filtered_array[i][0]
        Lambda1 = filtered_array[i][1]
        filtered[Lambda1 < 0] = 0
        filtered_array[i][0] = filtered

    # Return for every pixel the value of the scale(sigma) with the maximum
    # output pixel value
    out = np.max(filtered_array, axis=0)
    out[out <= 0] = 1

    return out[0]

<commit_msg>allocation fix + renaming lambdas in filter functions<commit_after>import numpy as np

__all__ = ['frangi', 'hessian']

def _frangi_hessian_common_filter(image, scale, scale_step, beta1, beta2):
    """This is an intermediate function for Frangi and Hessian filters.

    Shares the common code for Frangi and Hessian functions.

    Parameters
    ----------
    image : (N, M) ndarray
        Array with input image data.
    scale : tuple of floats, optional
        The range of sigmas used.
    scale_step : float, optional
        Step size between sigmas.
    beta1 : float, optional
        Frangi correction constant.
    beta2 : float, optional
        Frangi correction constant.
    black_ridges : boolean, optional
        If True (default), detects black ridges, if False - white ones.

    Returns
    -------
    filtered_list : list
        List of pre-filtered images.

    """

    # Import has to be here due to circular import error
    from ..feature import hessian_matrix, hessian_matrix_eigvals

    sigmas = np.arange(scale[0], scale[1], scale_step)

    if np.any(np.asarray(sigmas) < 0.0):
        raise ValueError("Sigma values less than zero are not valid")

    beta1 = 2 * beta1 ** 2
    beta2 = 2 * beta2 ** 2

    filtered_array = np.zeros((len(sigmas), np.shape(image)[0],
                               np.shape(image)[1]))
    lambdas_array = np.zeros((len(sigmas), np.shape(image)[0],
                              np.shape(image)[1]))

    # Filtering for all sigmas
    for i, sigma in enumerate(sigmas):
        # Make 2D hessian
        (Dxx, Dxy, Dyy) = hessian_matrix(image, sigma)

        # Correct for scale
        Dxx = (sigma ** 2) * Dxx
        Dxy = (sigma ** 2) * Dxy
        Dyy = (sigma ** 2) * Dyy

        # Calculate (abs sorted) eigenvalues and vectors
        (lambda1, lambda2) = hessian_matrix_eigvals(Dxx, Dxy, Dyy)

        # Compute some similarity measures
        lambda1[lambda1 == 0] = 1e-10
        rb = (lambda2 / lambda1) ** 2
        s2 = lambda1 ** 2 + lambda2 ** 2

        # Compute the output image
        filtered = np.exp(-rb / beta1) * (np.ones(np.shape(image)) -
                                          np.exp(-s2 / beta2))

        # Store the results in 3D matrices
        filtered_array[i] = filtered
        lambdas_array[i] = lambda1
    return filtered_array, lambdas_array

def frangi(image, scale=(1, 10), scale_step=2, beta1=0.5, beta2=15,
           black_ridges=True):
    """Filter an image with the Frangi filter.

    This filter can be used to detect continous edges, e.g. vessels,
    wrinkles, rivers. It can be used to calculate the fraction of the
    whole image containing such objects.

    Calculates the eigenvectors of the Hessian to compute the likeliness of
    an image region to vessels, according to the method described in _[1].

    Parameters
    ----------
    image : (N, M) ndarray
        Array with input image data.
    scale : tuple of floats, optional
        The range of sigmas used.
    scale_step : float, optional
        Step size between sigmas.
    beta1 : float, optional
        Frangi correction constant.
    beta2 : float, optional
        Frangi correction constant.
    black_ridges : boolean, optional
        Detect black ridges (default) set to true, for
        white ridges set to false.

    Returns
    -------
    out : (N, M) ndarray
        Filtered image (maximum of pixels across all scales).

    Notes
    -----
    Written by Marc Schrijver, 2/11/2001
    Re-Written by D. J. Kroon University of Twente (May 2009)

    References
    ----------
    .. [1] A. Frangi, W. Niessen, K. Vincken, and M. Viergever. "Multiscale
           vessel enhancement filtering," In LNCS, vol. 1496, pages 130-137,
           Germany, 1998. Springer-Verlag.
    .. [2] Kroon, D.J.: Hessian based frangi vesselness filter.
    .. [3] http://mplab.ucsd.edu/tutorials/gabor.pdf.
    """

    filtered, lambdas = _frangi_hessian_common_filter(image, scale, scale_step,
                                                      beta1, beta2)

    if black_ridges:
        filtered[lambdas < 0] = 0
    else:
        filtered[lambdas > 0] = 0

    # Return for every pixel the value of the scale(sigma) with the maximum
    # output pixel value

    return np.max(filtered, axis=0)

def hessian(image, scale=(1, 10), scale_step=2, beta1=0.5, beta2=15):
    """Filter an image with the Hessian filter.

    This filter can be used to detect continous edges, e.g. vessels,
    wrinkles, rivers. It can be used to calculate the fraction of the whole
    image containing such objects

    Almost equal to frangi filter, but uses alternative method of smoothing.
    Address _[1] to find the differences between Frangi and Hessian filters.

    Parameters
    ----------
    image : (N, M) ndarray
        Array with input image data.
    scale : tuple of floats, optional
        The range of sigmas used.
    scale_step : float, optional
        Step size between sigmas.
    beta1 : float, optional
        Frangi correction constant.
    beta2 : float, optional
        Frangi correction constant.

    Returns
    -------
    out : (N, M) ndarray
        Filtered image (maximum of pixels across all scales).

    Notes
    -----
    Written by Marc Schrijver, 2/11/2001
    Re-Written by D. J. Kroon University of Twente (May 2009)

    References
    ----------
    .. [1] Choon-Ching Ng, Moi Hoon Yap, Nicholas Costen and Baihua Li,
           "Automatic Wrinkle Detection using Hybrid Hessian Filter".
    """

    filtered, lambdas = _frangi_hessian_common_filter(image, scale, scale_step,
                                                      beta1, beta2)

    filtered[lambdas < 0] = 0

    # Return for every pixel the value of the scale(sigma) with the maximum
    # output pixel value
    out = np.max(filtered, axis=0)
    out[out <= 0] = 1

    return out

<|endoftext|>


<commit_before>"""
skimage.novice
==============
A special Python image submodule for beginners.

Description
-----------
``skimage.novice`` provides a simple image manipulation interface for
beginners.  It allows for easy loading, manipulating, and saving of image
files.

This module is primarily intended for teaching and differs significantly from
the normal, array-oriented image functions used by scikit-image.

.. note::

    This module uses the Cartesian coordinate system, where the origin is at
    the lower-left corner instead of the upper-right and the order is x, y
    instead of row, column.

Example
-------

We can create a Picture object open opening an image file
>>> from skimage import novice
>>> from skimage import data
>>> picture = novice.open(data.data_dir + '/chelsea.png')

Pictures know their format
>>> picture.format
'png'

... and where they came from
>>> picture.path.endswith('chelsea.png')
True

... and their size
>>> picture.size
(451, 300)
>>> picture.width
451

Changing `size` resizes the picture.
>>> picture.size = (45, 30)

You can iterate over pixels, which have RGB values between 0 and 255,
and know their location in the picture.
>>> for pixel in picture:
...     if (pixel.red > 128) and (pixel.x < picture.width):
...         pixel.red /= 2

Pictures know if they've been modified from the original file
>>> picture.modified
True
>>> picture.path
None

Pictures can be indexed like arrays
>>> picture[0:20, 0:20] = (0, 0, 0)

Saving the picture updates the path attribute, format, and modified state.
>>> picture.save('save-demo.jpg')
>>> picture.path.endswith('save-demo.jpg')
True
>>> picture.format
'jpeg'
>>> picture.modified
False

"""
from ._novice import Picture, open, colors, color_dict

__all__ = ['Picture', 'open', 'colors', 'color_dict']
<commit_msg>Fix novice doctest<commit_after>"""
skimage.novice
==============
A special Python image submodule for beginners.

Description
-----------
``skimage.novice`` provides a simple image manipulation interface for
beginners.  It allows for easy loading, manipulating, and saving of image
files.

This module is primarily intended for teaching and differs significantly from
the normal, array-oriented image functions used by scikit-image.

.. note::

    This module uses the Cartesian coordinate system, where the origin is at
    the lower-left corner instead of the upper-right and the order is x, y
    instead of row, column.

Example
-------

We can create a Picture object open opening an image file
>>> from skimage import novice
>>> from skimage import data
>>> picture = novice.open(data.data_dir + '/chelsea.png')

Pictures know their format
>>> picture.format
'png'

... and where they came from
>>> picture.path.endswith('chelsea.png')
True

... and their size
>>> picture.size
(451, 300)
>>> picture.width
451

Changing `size` resizes the picture.
>>> picture.size = (45, 30)

You can iterate over pixels, which have RGB values between 0 and 255,
and know their location in the picture.
>>> for pixel in picture:
...     if (pixel.red > 128) and (pixel.x < picture.width):
...         pixel.red /= 2

Pictures know if they've been modified from the original file
>>> picture.modified
True
>>> print(picture.path)
None

Pictures can be indexed like arrays
>>> picture[0:20, 0:20] = (0, 0, 0)

Saving the picture updates the path attribute, format, and modified state.
>>> picture.save('save-demo.jpg')
>>> picture.path.endswith('save-demo.jpg')
True
>>> picture.format
'jpeg'
>>> picture.modified
False

"""
from ._novice import Picture, open, colors, color_dict

__all__ = ['Picture', 'open', 'colors', 'color_dict']
<|endoftext|>


<commit_before>import os, sys, re, types, time
from aquests.lib  import pathtool, importer, evbus
import threading
from types import FunctionType as function
import copy
try:
	from django.utils import autoreload
except ImportError:
	pass

class Module:
	def __init__ (self, wasc, handler, bus, route, directory, libpath, pref = None):
		self.wasc = wasc
		self.bus = bus
		self.handler = handler
		self.pref = pref
		self.last_reloaded = time.time ()
		self.app = None
		self.django = False
		self.set_route (route)
		if type (libpath) is str:
			try:
				libpath, self.appname = libpath.split (":", 1)
			except ValueError:
				libpath, self.appname = libpath, "app"
			self.script_name = "%s.py" % libpath
			self.module, self.abspath = importer.importer (directory, libpath)
			self.start_app ()

		else:
			self.appname, self.module, self.abspath = "app", None, os.path.join (directory, 'dummy')
			self.app = libpath
			self.app.use_reloader = False
			self.start_app ()

	def __repr__ (self):
		return "<Module routing to %s at %x>" % (self.route, id(self))

	def mounted (self, was):
		app = self.app or getattr (self.module, self.appname)
		try: f = getattr (app, "onmounted")
		except AttributeError: pass
		else:
			f (was)

	def umount (self, was):
		app = self.app or getattr (self.module, self.appname)
		try: f = getattr (app, "onumount")
		except AttributeError: pass
		else:
			f (was)

	def get_callable (self):
		return self.app or getattr (self.module, self.appname)

	def start_app (self, reloded = False):
		func = None
		app = self.app or getattr (self.module, self.appname)
		self.django = str (app.__class__).find ("django.") != -1

		if self.pref:
			for k, v in copy.copy (self.pref).items ():
				if k == "config":
					if not hasattr (app, 'config'):
						app.config = v
					else:
						for k, v in copy.copy (self.pref.config).items ():
							app.config [k] = v
				else:
					setattr (app, k, v)

		if hasattr (app, "set_home"):
			app.set_home (os.path.dirname (self.abspath))
		if hasattr (app, "commit_events_to"):
			app.commit_events_to (self.bus)

		self.set_devel_env ()
		self.update_file_info ()

		try:
			if not reloded:
				func = app.start
			else:
				func = app.restart
		except AttributeError:
			pass

		if func:
			# temporary current handler
			self.wasc.handler = self.handler
			func (self.wasc, self.route)
			self.wasc.handler = None

	def cleanup (self):
		app = self.app or getattr (self.module, self.appname)
		try: app.cleanup ()
		except AttributeError: pass

	def set_devel_env (self):
		self.debug = False
		self.use_reloader = False
		app = self.app or getattr (self.module, self.appname)
		try: self.debug = app.debug
		except AttributeError: pass
		try: self.use_reloader = app.use_reloader
		except AttributeError: pass

	def update_file_info (self):
		if self.module is None:
			# app directly mounted
			return
		stat = os.stat (self.abspath)
		self.file_info = (stat.st_mtime, stat.st_size)

	def maybe_reload (self):
		if not self.use_reloader:
			return

		if time.time () - self.last_reloaded < 1.0:
			return

		reloadable = False
		if self.django:
			if autoreload.code_changed ():
				reloadable = True
		else:
			stat = os.stat (self.abspath)
			reloadable = self.file_info != (stat.st_mtime, stat.st_size)

		if reloadable:
			app = getattr (self.module, self.appname)
			if hasattr (app, "remove_events"):
				app.remove_events ()

			PRESERVED = []
			if hasattr (app, "PRESERVE_ON_RELOAD"):
				PRESERVED = [(attr, getattr (app, attr)) for attr in app.PRESERVES_ON_RELOAD]

			importer.reloader (self.module)
			self.start_app (reloded = True)
			newapp = getattr (self.module, self.appname)
			for attr, value in PRESERVED:
				setattr (newapp, attr, value)
			# remount
			self.mounted (self.wasc ())

		self.last_reloaded = time.time ()

	def set_route (self, route):
		route = route
		while route and route [-1] == "/":
			route = route [:-1]
		self.route = route + "/"
		self.route_len = len (self.route) - 1

	def get_route (self):
		return self.route

	def get_path_info (self, path):
		path_info = ("/" + path) [self.route_len:]
		return path_info

	def __call__ (self, env, start_response):
		self.use_reloader and self.maybe_reload ()
		app = self.app or getattr (self.module, self.appname)
		return app (env, start_response)

class ModuleManager:
	modules = {}
	def __init__(self, wasc, handler):
		self.wasc = wasc
		self.handler = handler
		self.modules = {}
		self.modnames = {}
		self.bus = evbus.EventBus ()
		self.cc = 0

	def __getitem__ (self, name):
		return self.modnames [name].get_callable ()

	def build_url (self, thing, *args, **kargs):
		a, b = thing.split (".", 1)
		return self.modnames [a].get_callable ().build_url (b, *args, **kargs)

	def add_module (self, route, directory, modname, pref):
		if modname in self.modnames:
			self.wasc.logger ("app", "app file name collision detected '%s'" % modname, "error")
			return

		if not route:
			route = "/"
		elif not route.endswith ("/"):
			route = route + "/"

		try:
			module = Module (self.wasc, self.handler, self.bus, route, directory, modname, pref)
		except:
			self.wasc.logger.trace ("app")
			self.wasc.logger ("app", "[error] application load failed: %s" % modname)
		else:
			self.wasc.logger ("app", "[info] application %s imported." % route)
			if route in self.modules:
				self.wasc.logger ("app", "[info] application route collision detected: %s at %s <-> %s" % (route, module.abspath, self.modules [route].abspath), "warn")
			self.modules [route] = module
			if type (modname) is str:
				# possibley direct app object
				self.modnames [modname.split (":", 1)[0]] = module

	def get_app (self, script_name):
		route = self.has_route (script_name)
		if route in (0, 1): # 404, 301
			return None

		try:
			app = self.modules [route]
		except KeyError:
			return None
		return app

	def has_route (self, script_name):
		# 0: 404
		# 1: 301 => /skitai => /skitai/

		# route string
		#script_name = script_name.encode ("utf8")
		if script_name == "/" and "/" in self.modules:
			return "/"

		cands = []
		for route in self.modules:
			if script_name == route:
				cands.append (route)
			elif script_name + "/" == route:
				return 1
			elif script_name.startswith (route [-1] != "/" and route + "/" or route):
				cands.append (route)

		if cands:
			if len (cands) == 1:
				return cands [0]
			cands.sort (key = lambda x: len (x))
			return cands [-1]

		elif "/" in self.modules:
			return "/"

		return 0

	def unload (self, route):
		module = self.modules [route]
		self.wasc.logger ("app", "[info] unloading app: %s" % route)
		try:
			self.wasc.logger ("app", "[info] ..cleanup app: %s" % route)
			module.cleanup ()
		except AttributeError:
			pass
		except:
			self.wasc.logger.trace ("app")
		del module
		del self.modules [route]

	def cleanup (self):
		self.wasc.logger ("app", "[info] cleanup apps")
		for route, module in list(self.modules.items ()):
			try:
				self.wasc.logger ("app", "[info] ..cleanup app: %s" % route)
				module.cleanup ()
			except AttributeError:
				pass
			except:
				self.wasc.logger.trace ("app")

	def status (self):
		d = {}
		for path, module in list(self.modules.items ()):
			d ['%s' % (path, path)] = module.abspath
		return d

<commit_msg>fix reloading app<commit_after>import os, sys, re, types, time
from aquests.lib  import pathtool, importer, evbus
import threading
from types import FunctionType as function
import copy
try:
	from django.utils import autoreload
except ImportError:
	pass

class Module:
	def __init__ (self, wasc, handler, bus, route, directory, libpath, pref = None):
		self.wasc = wasc
		self.bus = bus
		self.handler = handler
		self.pref = pref
		self.last_reloaded = time.time ()
		self.app = None
		self.django = False
		self.set_route (route)
		self.directory = directory
		if type (libpath) is str:
			try:
				libpath, self.appname = libpath.split (":", 1)
			except ValueError:
				libpath, self.appname = libpath, "app"
			self.libpath = libpath
			self.script_name = "%s.py" % libpath
			self.module, self.abspath = importer.importer (directory, libpath)
			self.start_app ()

		else:
			self.appname, self.module, self.abspath = "app", None, os.path.join (directory, 'dummy')
			self.app = libpath
			self.app.use_reloader = False
			self.start_app ()

	def __repr__ (self):
		return "<Module routing to %s at %x>" % (self.route, id(self))

	def mounted (self, was):
		app = self.app or getattr (self.module, self.appname)
		try: f = getattr (app, "onmounted")
		except AttributeError: pass
		else:
			f (was)

	def umount (self, was):
		app = self.app or getattr (self.module, self.appname)
		try: f = getattr (app, "onumount")
		except AttributeError: pass
		else:
			f (was)

	def get_callable (self):
		return self.app or getattr (self.module, self.appname)

	def start_app (self, reloded = False):
		func = None
		app = self.app or getattr (self.module, self.appname)
		self.django = str (app.__class__).find ("django.") != -1

		if self.pref:
			for k, v in copy.copy (self.pref).items ():
				if k == "config":
					if not hasattr (app, 'config'):
						app.config = v
					else:
						for k, v in copy.copy (self.pref.config).items ():
							app.config [k] = v
				else:
					setattr (app, k, v)

		if hasattr (app, "set_home"):
			app.set_home (os.path.dirname (self.abspath))
		if hasattr (app, "commit_events_to"):
			app.commit_events_to (self.bus)

		self.set_devel_env ()
		self.update_file_info ()

		try:
			if not reloded:
				func = app.start
			else:
				func = app.restart
		except AttributeError:
			pass

		if func:
			# temporary current handler
			self.wasc.handler = self.handler
			func (self.wasc, self.route)
			self.wasc.handler = None

	def cleanup (self):
		app = self.app or getattr (self.module, self.appname)
		try: app.cleanup ()
		except AttributeError: pass

	def set_devel_env (self):
		self.debug = False
		self.use_reloader = False
		app = self.app or getattr (self.module, self.appname)
		try: self.debug = app.debug
		except AttributeError: pass
		try: self.use_reloader = app.use_reloader
		except AttributeError: pass

	def update_file_info (self):
		if self.module is None:
			# app directly mounted
			return
		stat = os.stat (self.abspath)
		self.file_info = (stat.st_mtime, stat.st_size)

	def maybe_reload (self):
		if not self.use_reloader:
			return

		if time.time () - self.last_reloaded < 1.0:
			return

		reloadable = False
		if self.django:
			if autoreload.code_changed ():
				reloadable = True
		else:
			stat = os.stat (self.abspath)
			reloadable = self.file_info != (stat.st_mtime, stat.st_size)

		if reloadable:
			app = getattr (self.module, self.appname)
			if hasattr (app, "remove_events"):
				app.remove_events ()

			PRESERVED = []
			if hasattr (app, "PRESERVE_ON_RELOAD"):
				PRESERVED = [(attr, getattr (app, attr)) for attr in app.PRESERVES_ON_RELOAD]

			self.module, self.abspath = importer.reimporter (self.module, self.directory, self.libpath)
			self.start_app (reloded = True)
			newapp = getattr (self.module, self.appname)
			for attr, value in PRESERVED:
				setattr (newapp, attr, value)
			# remount
			self.mounted (self.wasc ())

		self.last_reloaded = time.time ()

	def set_route (self, route):
		route = route
		while route and route [-1] == "/":
			route = route [:-1]
		self.route = route + "/"
		self.route_len = len (self.route) - 1

	def get_route (self):
		return self.route

	def get_path_info (self, path):
		path_info = ("/" + path) [self.route_len:]
		return path_info

	def __call__ (self, env, start_response):
		self.use_reloader and self.maybe_reload ()
		app = self.app or getattr (self.module, self.appname)
		return app (env, start_response)

class ModuleManager:
	modules = {}
	def __init__(self, wasc, handler):
		self.wasc = wasc
		self.handler = handler
		self.modules = {}
		self.modnames = {}
		self.bus = evbus.EventBus ()
		self.cc = 0

	def __getitem__ (self, name):
		return self.modnames [name].get_callable ()

	def build_url (self, thing, *args, **kargs):
		a, b = thing.split (".", 1)
		return self.modnames [a].get_callable ().build_url (b, *args, **kargs)

	def add_module (self, route, directory, modname, pref):
		if modname in self.modnames:
			self.wasc.logger ("app", "app file name collision detected '%s'" % modname, "error")
			return

		if not route:
			route = "/"
		elif not route.endswith ("/"):
			route = route + "/"

		try:
			module = Module (self.wasc, self.handler, self.bus, route, directory, modname, pref)
		except:
			self.wasc.logger.trace ("app")
			self.wasc.logger ("app", "[error] application load failed: %s" % modname)
		else:
			self.wasc.logger ("app", "[info] application %s imported." % route)
			if route in self.modules:
				self.wasc.logger ("app", "[info] application route collision detected: %s at %s <-> %s" % (route, module.abspath, self.modules [route].abspath), "warn")
			self.modules [route] = module
			if type (modname) is str:
				# possibley direct app object
				self.modnames [modname.split (":", 1)[0]] = module

	def get_app (self, script_name):
		route = self.has_route (script_name)
		if route in (0, 1): # 404, 301
			return None

		try:
			app = self.modules [route]
		except KeyError:
			return None
		return app

	def has_route (self, script_name):
		# 0: 404
		# 1: 301 => /skitai => /skitai/

		# route string
		#script_name = script_name.encode ("utf8")
		if script_name == "/" and "/" in self.modules:
			return "/"

		cands = []
		for route in self.modules:
			if script_name == route:
				cands.append (route)
			elif script_name + "/" == route:
				return 1
			elif script_name.startswith (route [-1] != "/" and route + "/" or route):
				cands.append (route)

		if cands:
			if len (cands) == 1:
				return cands [0]
			cands.sort (key = lambda x: len (x))
			return cands [-1]

		elif "/" in self.modules:
			return "/"

		return 0

	def unload (self, route):
		module = self.modules [route]
		self.wasc.logger ("app", "[info] unloading app: %s" % route)
		try:
			self.wasc.logger ("app", "[info] ..cleanup app: %s" % route)
			module.cleanup ()
		except AttributeError:
			pass
		except:
			self.wasc.logger.trace ("app")
		del module
		del self.modules [route]

	def cleanup (self):
		self.wasc.logger ("app", "[info] cleanup apps")
		for route, module in list(self.modules.items ()):
			try:
				self.wasc.logger ("app", "[info] ..cleanup app: %s" % route)
				module.cleanup ()
			except AttributeError:
				pass
			except:
				self.wasc.logger.trace ("app")

	def status (self):
		d = {}
		for path, module in list(self.modules.items ()):
			d ['%s' % (path, path)] = module.abspath
		return d

<|endoftext|>


<commit_before># Copyright 2020 Google LLC
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd

"""
The code in this file provides a drop-in replacement for spanner_v1.Transaction,
but one that auto-refreshes every 8.5 seconds, to deal with Cloud Spanner's server's
max idle time of 10 seconds, per:
    https://cloud.google.com/spanner/docs/reference/rest/v1/TransactionOptions#idle-transactions

It handles concurrency concerns by using an event loop, a queue and callbacks. If the queue
is empty for 8.5 seconds, it'll ping Cloud Spanner by sending the recommended:
    execute_sql('SELECT 1')
and then reading the result back.
"""

import queue
import threading
import time

class PeriodicAutoRefresher:
    def __init__(self, period_secs=10, ping_fn=None):
        self.__period_secs = period_secs
        self.__done = threading.Event()
        self.__Q = queue.Queue()
        self.__ping_fn = ping_fn
        self.__start_time = time.time()

        pth = threading.Thread(target=self.__event_loop, name='period-auto-refresh')
        pth.start()
        self.__pth = pth

    def __event_loop(self):
        while True:
            if not self.__still_running():
                return

            try:
                callback, fn, args, kwargs = self.__Q.get(block=True, timeout=self.__period_secs)
                res, exc = None, None

                try:
                    res = fn(*args, **kwargs)
                except Exception as e:
                    exc = e
                finally:
                    callback(res, exc)
            except queue.Empty:
                self.__ping_fn()

    def __still_running(self):
        return not self.__done.is_set()

    def stop(self):
        self.__done.set()
        self.__pth.join()

    def run_op(self, callback, fn, *args, **kwargs):
        self.__Q.put_nowait((callback, fn, args, kwargs))

class PeriodicAutoRefreshingTransaction:
    """
    PeriodicAutoRefreshingTransaction is the drop-in replacement for spanner_v1.Transaction
    but with a max-idle duration of 8.5 seconds, since the last use time of the underlying
    Transaction, else we'll perform a ping to Cloud Spanner with 'SELECT 1'.

    It becomes active after .begin() has been invoked.
    """

    def __init__(self, txn):
        self.__txn = txn

    def begin(self):
        res = self.__txn.begin()
        self.__par = PeriodicAutoRefresher(period_secs=8.5, ping_fn=self.__ping)
        return res

    def __ping(self):
        print('Pinging Cloud Spanner at %s' % time.time())
        res = self.__txn.execute_sql('SELECT 1')
        if res:
            for it in res:
                _ = it

    def execute_sql(self, *args, **kwargs):
        return self.__on_event_queue(self.__txn.execute_sql, *args, **kwargs)

    def execute_update(self, *args, **kwargs):
        return self.__on_event_queue(self.__txn.execute_update, *args, **kwargs)

    def commit(self):
        res = self.__on_event_queue(self.__txn.commit)
        self.__par.stop()
        return res

    def rollback(self):
        res = self.__on_event_queue(self.__txn.rollback)
        self.__par.stop()
        return res

    def was_committed_or_rolledback(self):
        # For now it is alright to access Transaction._rolled_back
        # even though it is unexported. We've filed a follow-up issue:
        #   https://github.com/googleapis/python-spanner/issues/13
        return self.__on_event_queue(lambda txn: txn.committed or txn._rolled_back, self.__txn)

    def __on_event_queue(self, fn, *args, **kwargs):
        ready = threading.Event()
        res_exc = {}

        # Using a lambda here because a defined closure would have scope/visibility
        # problems trying to set res_exc, even if we used 'global res_exc'. A lambda solves
        # the issue due to different scoping.
        # We have to propagate the underlying results and exceptions from
        # the asynchronously running callback, converting it to a synchronous call.
        callback = lambda in_res, in_exc: (res_exc.setdefault('res', in_res), res_exc.setdefault('exc', in_exc), ready.set())  # noqa

        self.__par.run_op(callback, fn, *args, **kwargs)
        ready.wait()

        res, exc = res_exc['res'], res_exc['exc']

        if exc:
            raise exc

        return res
<commit_msg>dbapi: use only mutexes for synchronization in auto-refresh Transaction<commit_after># Copyright 2020 Google LLC
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd

"""
The code in this file provides a drop-in replacement for spanner_v1.Transaction,
but one that auto-refreshes every 8.5 seconds, to deal with Cloud Spanner's server's
max idle time of 10 seconds, per:
    https://cloud.google.com/spanner/docs/reference/rest/v1/TransactionOptions#idle-transactions

It handles concurrency concerns by using an event loop, a queue and callbacks. If the queue
is empty for 8.5 seconds, it'll ping Cloud Spanner by sending the recommended:
    execute_sql('SELECT 1')
and then reading the result back.
"""

import queue
import threading
import time

class PeriodicAutoRefresher:
    TICK = 'tick'

    def __init__(self, period_secs=10, ping_fn=None):
        self.__period_secs = period_secs
        self.__done = threading.Event()
        self.__Q = queue.Queue()
        self.__ping_fn = ping_fn
        self.__start_time = time.time()

        pth = threading.Thread(target=self.__event_loop, name='period-auto-refresh')
        pth.start()
        self.__pth = pth

    def __still_running(self):
        return not self.__done.is_set()

    def stop(self):
        self.__done.set()
        self.__pth.join()

    def record_tick(self):
        self.__Q.put_nowait(self.TICK)

class PeriodicAutoRefreshingTransaction:
    """
    PeriodicAutoRefreshingTransaction is the drop-in replacement for spanner_v1.Transaction
    but with a max-idle duration of 8.5 seconds, since the last use time of the underlying
    Transaction, else we'll perform a ping to Cloud Spanner with 'SELECT 1'.

    It becomes active after .begin() has been invoked.
    """

    def __init__(self, txn):
        self.__txn = txn
        self.__running = False
        self.__lock = threading.Lock()
        self.__period_secs = 8.5

    def begin(self):
        res = self.__txn.begin()
        self.__running = True
        self.__start_time = time.time()
        self.__last_active_time = 0

        pth = threading.Thread(target=self.__event_loop, name='periodic-auto-refresh')
        pth.start()
        self.__pth = pth

        return res

    def __event_loop(self):
        while True:
            time.sleep(self.__period_secs)

            self.__lock.acquire()
            running = self.__running
            diff_secs = time.time() - self.__last_active_time
            if not running:
                self.__lock.release()
                return

            if diff_secs >= self.__period_secs:
                self.__ping_locked()
            self.__lock.release()

    def __ping_locked(self):
        print('Pinging Cloud Spanner at %s' % time.time() - self.__start_time)
        res = self.__txn.execute_sql('SELECT 1')
        if res:
            for it in res:
                _ = it

    def execute_sql(self, *args, **kwargs):
        self.__record_last_active_time()
        return self.__txn.execute_sql(*args, **kwargs)

    def execute_update(self, *args, **kwargs):
        self.__record_last_active_time()
        return self.__txn.execute_update(*args, **kwargs)

    def commit(self):
        self.__stop()
        return self.__txn.commit()

    def rollback(self):
        self.__stop()
        return self.__txn.rollback()

    def __stop(self):
        self.__lock.acquire()
        self.__running = False
        self.__lock.release()
        self.__pth.join()

    def __record_last_active_time(self):
        self.__lock.acquire()
        self.__last_active_time = time.time()
        self.__lock.release()

    def was_committed_or_rolledback(self):
        # For now it is alright to access Transaction._rolled_back
        # even though it is unexported. We've filed a follow-up issue:
        #   https://github.com/googleapis/python-spanner/issues/13
        self.__lock.acquire()
        ok = self.__txn.committed or self.__txn._rolled_back
        self.__lock.release()
        return ok
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
===============================================================================
Structure Generator base classes (:mod:`sknano.generators._base`)
===============================================================================

.. currentmodule:: sknano.generators._base

"""
from __future__ import absolute_import, division, print_function
__docformat__ = 'restructuredtext en'

import copy
import os

try:
    from sknano.core.atoms import KDTAtom as Atom, KDTAtoms as Atoms
except ImportError:
    from sknano.core.atoms import XAtom as Atom, XAtoms as Atoms

from sknano.io import StructureWriter, default_structure_format, \
    supported_structure_formats

__all__ = ['Atom', 'Atoms', 'GeneratorMixin', 'STRUCTURE_GENERATORS']

STRUCTURE_GENERATORS = ('SWNTGenerator', 'SWNTBundleGenerator',
                        'MWNTGenerator', 'MWNTBundleGenerator',
                        'GrapheneGenerator', 'BilayerGrapheneGenerator')

class GeneratorMixin(object):
    """Base mixin class for generator classes"""

    @property
    def atoms(self):
        """Return structure :class:`~sknano.core.atoms.Atoms`."""
        return self._atoms

    @atoms.setter
    def atoms(self, value):
        if not isinstance(value, Atoms):
            raise TypeError('Expected an `Atoms` object.')
        self._atoms = value

    @atoms.deleter
    def atoms(self):
        del self._atoms

    def save_data(self, fname=None, outpath=None, structure_format=None,
                  rotation_angle=None, rot_axis=None, anchor_point=None,
                  deg2rad=True, center_CM=True, savecopy=True, **kwargs):
        """Save structure data.

        .. todo::

           Use the unit cell to set the bounds on output.

        Parameters
        ----------
        fname : {None, str}, optional
            file name string
        outpath : str, optional
            Output path for structure data file.
        structure_format : {None, str}, optional
            chemical file format of saved structure data. Must be one of:

                - `xyz`
                - `data`

            If `None`, then guess based on `fname` file extension or
            default to `xyz` format.
        rotation_angle : {None, float}, optional
            Angle of rotation
        rot_axis : {'x', 'y', 'z'}, optional
            Rotation axis
        anchor_point : array_like, optional
            Rotation axis origin
        deg2rad : bool, optional
            Convert `rotation_angle` from degrees to radians.
        center_CM : bool, optional
            Center center-of-mass on origin.

        """
        if fname.endswith(supported_structure_formats) and \
                structure_format is None:
            for ext in supported_structure_formats:
                if fname.endswith(ext):
                    structure_format = ext
                    break
        elif structure_format is None or \
            structure_format not in supported_structure_formats or \
            (not fname.endswith(supported_structure_formats) and
             structure_format not in supported_structure_formats):
            structure_format = default_structure_format

        if not fname.endswith(structure_format):
            fname += '.' + structure_format

        if outpath is not None:
            self.fpath = os.path.join(outpath, fname)

        #self._structure_format = structure_format

        if savecopy:
            atoms = copy.deepcopy(self.atoms)
        else:
            atoms = self.atoms

        if center_CM:
            atoms.center_CM()

        if rotation_angle is not None:
            atoms.rotate(angle=rotation_angle, rot_axis=rot_axis,
                         anchor_point=anchor_point, deg2rad=deg2rad)

        StructureWriter.write(fname=fname, outpath=outpath, atoms=atoms,
                              structure_format=structure_format)
<commit_msg>Adding the self.fname assignment back into code.<commit_after># -*- coding: utf-8 -*-
"""
===============================================================================
Structure Generator base classes (:mod:`sknano.generators._base`)
===============================================================================

.. currentmodule:: sknano.generators._base

"""
from __future__ import absolute_import, division, print_function
__docformat__ = 'restructuredtext en'

import copy
import os

try:
    from sknano.core.atoms import KDTAtom as Atom, KDTAtoms as Atoms
except ImportError:
    from sknano.core.atoms import XAtom as Atom, XAtoms as Atoms

from sknano.io import StructureWriter, default_structure_format, \
    supported_structure_formats

__all__ = ['Atom', 'Atoms', 'GeneratorMixin', 'STRUCTURE_GENERATORS']

STRUCTURE_GENERATORS = ('SWNTGenerator', 'SWNTBundleGenerator',
                        'MWNTGenerator', 'MWNTBundleGenerator',
                        'GrapheneGenerator', 'BilayerGrapheneGenerator')

class GeneratorMixin(object):
    """Base mixin class for generator classes"""

    @property
    def atoms(self):
        """Return structure :class:`~sknano.core.atoms.Atoms`."""
        return self._atoms

    @atoms.setter
    def atoms(self, value):
        if not isinstance(value, Atoms):
            raise TypeError('Expected an `Atoms` object.')
        self._atoms = value

    @atoms.deleter
    def atoms(self):
        del self._atoms

    def save_data(self, fname=None, outpath=None, structure_format=None,
                  rotation_angle=None, rot_axis=None, anchor_point=None,
                  deg2rad=True, center_CM=True, savecopy=True, **kwargs):
        """Save structure data.

        .. todo::

           Use the unit cell to set the bounds on output.

        Parameters
        ----------
        fname : {None, str}, optional
            file name string
        outpath : str, optional
            Output path for structure data file.
        structure_format : {None, str}, optional
            chemical file format of saved structure data. Must be one of:

                - `xyz`
                - `data`

            If `None`, then guess based on `fname` file extension or
            default to `xyz` format.
        rotation_angle : {None, float}, optional
            Angle of rotation
        rot_axis : {'x', 'y', 'z'}, optional
            Rotation axis
        anchor_point : array_like, optional
            Rotation axis origin
        deg2rad : bool, optional
            Convert `rotation_angle` from degrees to radians.
        center_CM : bool, optional
            Center center-of-mass on origin.

        """
        if fname.endswith(supported_structure_formats) and \
                structure_format is None:
            for ext in supported_structure_formats:
                if fname.endswith(ext):
                    structure_format = ext
                    break
        elif structure_format is None or \
            structure_format not in supported_structure_formats or \
            (not fname.endswith(supported_structure_formats) and
             structure_format not in supported_structure_formats):
            structure_format = default_structure_format

        if not fname.endswith(structure_format):
            fname += '.' + structure_format
        self.fname = fname

        if outpath is not None:
            fpath = os.path.join(outpath, fname)
        else:
            fpath = os.path.join(os.getcwd(), fname)
        self.fpath = fpath

        #self._structure_format = structure_format

        if savecopy:
            atoms = copy.deepcopy(self.atoms)
        else:
            atoms = self.atoms

        if center_CM:
            atoms.center_CM()

        if rotation_angle is not None:
            atoms.rotate(angle=rotation_angle, rot_axis=rot_axis,
                         anchor_point=anchor_point, deg2rad=deg2rad)

        StructureWriter.write(fname=fname, outpath=outpath, atoms=atoms,
                              structure_format=structure_format)
<|endoftext|>


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

from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import
from __future__ import print_function

"""Test dataset and fake auto generated trajectories.

When data function end with _temp. The file is being copied to a temporary
directory before its path is returned.
"""

import os
import tempfile
import shutil
import pandas as pd
import sys

from ..io.utils import load_img_list

data_path = os.path.dirname(os.path.realpath(__file__))

# Trajectories generator

from .trajectories_generator import directed_trajectories_generator
from .trajectories_generator import brownian_trajectories_generator

__all__ = ['directed_trajectories_generator',
           'brownian_trajectories_generator',
           'CZT_peaks',
           'sample_ome',
           'tubhiswt_4D',
           'stack_list_dir',
           'stack_list',
           'TZ_nucleus', 'TC_BF_cells',
           'metadata_json',
           'sample_h5',
           'sample_h5_temp',
           'brownian_trajs_df',
           'trackmate_xml_temp',
           'trackmate_xml',
           'with_gaps_df']

# Image files

def CZT_peaks():
    """OME Tiff with fluo spots and CTZ dimensions.
    """
    return os.path.join(data_path, "CZT_peaks.ome.tif")

def sample_ome():
    """OME Tiff with fluo spots and cells in BF and CTZ dimensions.
    """
    return os.path.join(data_path, "sample.ome.tif")

def tubhiswt_4D():
    """OME XML file from OME sample dataset.
    """
    return os.path.join(data_path, "tubhiswt-4D.ome.xml")

def stack_list_dir():
    """
    """
    return os.path.join(data_path, "stack_list")

def stack_list():
    """
    """
    dirname = stack_list_dir()
    file_list = load_img_list(dirname)
    return file_list

def TZ_nucleus():
    """
    """
    return os.path.join(data_path, "TZ_nucleus.ome.tif")

def TC_BF_cells():
    """
    """
    return os.path.join(data_path, "TC_BF_cells.ome.tif")

# JSON files

def metadata_json():
    """
    """
    return os.path.join(data_path, "metadata.json")

# HDF5 files

def nuclei_h5():
    return os.path.join(data_path, "nuclei.h5")

def nuclei_h5_temp():
    """
    """
    d = tempfile.gettempdir()
    f_ori = os.path.join(data_path, "nuclei.h5")
    f_dest = os.path.join(d, "nuclei.h5")
    shutil.copy(f_ori, f_dest)
    return f_dest

def sample_h5():
    """
    """
    if sys.version_info[0] < 3:
        return os.path.join(data_path, "sample_py2.h5")
    return os.path.join(data_path, "sample.h5")

def sample_h5_temp():
    """
    """
    d = tempfile.gettempdir()
    f_ori = sample_h5()
    f_dest = os.path.join(d, "sample.h5")
    shutil.copy(f_ori, f_dest)
    return f_dest

def brownian_trajs_df():
    """
    """
    store_path = os.path.join(data_path, "brownian_trajectories.h5")
    with pd.get_store(store_path) as store:
        trajs = store['trajs']
    return trajs

def with_gaps_df():
    """
    """
    with pd.get_store(os.path.join(data_path, "with_gaps.h5")) as store:
        trajs = store['trajs']
    return trajs

# XML files
def trackmate_xml():
    return os.path.join(data_path, "trackmate_example.xml")

def trackmate_xml_temp():
    """
    """
    d = tempfile.gettempdir()
    f_ori = os.path.join(data_path, "trackmate_example.xml")
    f_dest = os.path.join(d, "trackmate_example.xml")
    shutil.copy(f_ori, f_dest)
    return f_dest
<commit_msg>change in test data for stack list<commit_after>
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import
from __future__ import print_function

"""Test dataset and fake auto generated trajectories.

When data function end with _temp. The file is being copied to a temporary
directory before its path is returned.
"""

import os
import tempfile
import shutil
import pandas as pd
import sys

from ..io.utils import load_img_list

data_path = os.path.dirname(os.path.realpath(__file__))

# Trajectories generator

from .trajectories_generator import directed_trajectories_generator
from .trajectories_generator import brownian_trajectories_generator

__all__ = ['directed_trajectories_generator',
           'brownian_trajectories_generator',
           'CZT_peaks',
           'sample_ome',
           'tubhiswt_4D',
           'stack_list_dir',
           'stack_list',
           'TZ_nucleus', 'TC_BF_cells',
           'metadata_json',
           'sample_h5',
           'sample_h5_temp',
           'brownian_trajs_df',
           'trackmate_xml_temp',
           'trackmate_xml',
           'with_gaps_df']

# Image files

def CZT_peaks():
    """OME Tiff with fluo spots and CTZ dimensions.
    """
    return os.path.join(data_path, "CZT_peaks.ome.tif")

def sample_ome():
    """OME Tiff with fluo spots and cells in BF and CTZ dimensions.
    """
    return os.path.join(data_path, "sample.ome.tif")

def tubhiswt_4D():
    """OME XML file from OME sample dataset.
    """
    return os.path.join(data_path, "tubhiswt-4D.ome.xml")

def stack_list_dir():
    """
    """
    return os.path.join(data_path, "stack_list")

def stack_list():
    """
    """
    dirname = stack_list_dir()
    file_list = load_img_list(dirname)
    return file_list

def TZ_nucleus():
    """
    """
    return os.path.join(data_path, "TZ_nucleus.ome.tif")

def TC_BF_cells():
    """
    """
    return os.path.join(data_path, "TC_BF_cells.ome.tif")

# JSON files

def metadata_json():
    """
    """
    return os.path.join(data_path, "metadata.json")

# HDF5 files

def nuclei_h5():
    stk_list = stack_list_dir()
    return os.path.join(data_path, stk_list, "Stack-1.h5")

def nuclei_h5_temp():
    """
    """
    d = tempfile.gettempdir()
    f_ori = nuclei_h5()
    f_dest = os.path.join(d, "nuclei.h5")
    shutil.copy(f_ori, f_dest)
    return f_dest

def sample_h5():
    """
    """
    if sys.version_info[0] < 3:
        return os.path.join(data_path, "sample_py2.h5")
    return os.path.join(data_path, "sample.h5")

def sample_h5_temp():
    """
    """
    d = tempfile.gettempdir()
    f_ori = sample_h5()
    f_dest = os.path.join(d, "sample.h5")
    shutil.copy(f_ori, f_dest)
    return f_dest

def brownian_trajs_df():
    """
    """
    store_path = os.path.join(data_path, "brownian_trajectories.h5")
    with pd.get_store(store_path) as store:
        trajs = store['trajs']
    return trajs

def with_gaps_df():
    """
    """
    with pd.get_store(os.path.join(data_path, "with_gaps.h5")) as store:
        trajs = store['trajs']
    return trajs

# XML files
def trackmate_xml():
    return os.path.join(data_path, "trackmate_example.xml")

def trackmate_xml_temp():
    """
    """
    d = tempfile.gettempdir()
    f_ori = os.path.join(data_path, "trackmate_example.xml")
    f_dest = os.path.join(d, "trackmate_example.xml")
    shutil.copy(f_ori, f_dest)
    return f_dest
<|endoftext|>


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

"""
How to run:
    $ python examples/client.py
"""

from bson_rpc import connect

if __name__ == '__main__':
    #conn = connect() # LOCAL
    #conn = connect('127.0.0.1') # STAND-ALONE
    #conn = connect('127.0.0.1', 8181) # STAND-ALONE
    #conn = connect('10.0.0.1', '127.0.0.1', 8181) # STAND-BY
    conn = connect(['10.0.0.1', '10.0.0.2', '127.0.0.1', '10.0.0.3']) # LOAD-BALANCE
    #conn = connect(['10.0.0.1', '10.0.0.2', '127.0.0.1', '10.0.0.3'], 8181) # LOAD-BALANCE
    #conn = connect('ipc:///tmp/bson_rpc')
    #print('connected to server %s' % host)

    conn.use_service(['add', 'echo']);

    err, res = conn.add(1,2)
    print('result: %s' % str(res))

    err, res = conn.echo('你好')
    print('result: %s' % str(res))

    err, res = conn.__stats__()
    print('result: %s' % str(res))

    conn.disconnect();
    #print('disconnected from server %s' % host)
<commit_msg>rename conn to proxy<commit_after>#!/usr/bin/env python
#encoding:utf-8

"""
How to run:
    $ python examples/client.py
"""

from bson_rpc import connect

if __name__ == '__main__':
    #proxy = connect() # LOCAL
    #proxy = connect('127.0.0.1') # STAND-ALONE
    #proxy = connect('127.0.0.1', 8181) # STAND-ALONE
    #proxy = connect('10.0.0.1', '127.0.0.1', 8181) # STAND-BY
    proxy = connect(['10.0.0.1', '10.0.0.2', '127.0.0.1', '10.0.0.3']) # LOAD-BALANCE
    #proxy = connect(['10.0.0.1', '10.0.0.2', '127.0.0.1', '10.0.0.3'], 8181) # LOAD-BALANCE
    #proxy = connect('ipc:///tmp/bson_rpc')
    #print('proxyected to server %s' % host)

    proxy.use_service(['add', 'echo']);

    err, res = proxy.add(1,2)
    print('result: %s' % str(res))

    err, res = proxy.echo('你好')
    print('result: %s' % str(res))

    err, res = proxy.__stats__()
    print('result: %s' % str(res))

    proxy.disconnect();
    #print('disproxyected from server %s' % host)
<|endoftext|>


<commit_before>"""hug/authentication.py

Provides the basic built-in authentication helper functions

Copyright (C) 2016  Timothy Edmund Crosley

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

"""
from __future__ import absolute_import

import base64
import binascii

from falcon import HTTPUnauthorized

def authenticator(function):
    """Wraps authentication logic, verify_user through to the authentication function.

    The verify_user function passed in should accept an API key and return a user object to
    store in the request context if authentication succeeded.
    """

    def wrapper(verify_user):
        def authenticate(request, response, **kwargs):
            result = function(request, response, verify_user, **kwargs)
            if result is None:
                raise HTTPUnauthorized('Authentication Required',
                                       'Please provide valid {0} credentials'.format(function.__doc__.splitlines()[0]))

            if result is False:
                raise HTTPUnauthorized('Invalid Authentication',
                                       'Provided {0} credentials were invalid'.format(function.__doc__.splitlines()[0]))

            request.context['user'] = result
            return True

        authenticate.__doc__ = function.__doc__
        return authenticate

    return wrapper

@authenticator
def basic(request, response, verify_user, **kwargs):
    """Basic HTTP Authentication"""
    http_auth = request.auth
    response.set_header('WWW-Authenticate', 'Basic')
    if http_auth is None:
        return

    if isinstance(http_auth, bytes):
        http_auth = http_auth.decode('utf8')
    try:
        auth_type, user_and_key = http_auth.split(' ', 1)
    except ValueError:
        raise HTTPUnauthorized('Authentication Error',
                               'Authentication header is improperly formed')

    if auth_type.lower() == 'basic':
        try:
            user_id, key = base64.decodebytes(bytes(user_and_key.strip(), 'utf8')).decode('utf8').split(':', 1)
            user = verify_user(user_id, key)
            if user:
                response.set_header('WWW-Authenticate', '')
                return user
        except (binascii.Error, ValueError):
            raise HTTPUnauthorized('Authentication Error',
                                   'Unable to determine user and password with provided encoding')
    return False

@authenticator
def api_key(request, response, verify_user, **kwargs):
    """API Key Header Authentication

    The verify_user function passed in to ths authenticator shall receive an
    API key as input, and return a user object to store in the request context
    if the request was successful.
    """
    api_key = request.get_header('X-Api-Key')

    if api_key:
        user = verify_user(api_key)
        if user:
            return user
        else:
            return False
    else:
        return None

@authenticator
def token(request, response, verify_user, **kwargs):
    """Token verification

     Checks for the Authorization header and verifies using the verify_user function
    """
    token = request.get_header('Authorization')
    if token:
        verified_token = verify_user(token)
        if verified_token:
            return verified_token
        else:
            return False
    return None

def verify(user, password):
    """Returns a simple verification callback that simply verifies that the users and password match that provided"""
    def verify_user(user_name, user_password):
        if user_name == user and user_password == password:
            return user_name
        return False

    return verify_user
<commit_msg>Fix spacing<commit_after>"""hug/authentication.py

Provides the basic built-in authentication helper functions

Copyright (C) 2016  Timothy Edmund Crosley

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

"""
from __future__ import absolute_import

import base64
import binascii

from falcon import HTTPUnauthorized

def authenticator(function):
    """Wraps authentication logic, verify_user through to the authentication function.

    The verify_user function passed in should accept an API key and return a user object to
    store in the request context if authentication succeeded.
    """

    def wrapper(verify_user):
        def authenticate(request, response, **kwargs):
            result = function(request, response, verify_user, **kwargs)
            if result is None:
                raise HTTPUnauthorized('Authentication Required',
                                       'Please provide valid {0} credentials'.format(function.__doc__.splitlines()[0]))

            if result is False:
                raise HTTPUnauthorized('Invalid Authentication',
                                       'Provided {0} credentials were invalid'.format(function.__doc__.splitlines()[0]))

            request.context['user'] = result
            return True

        authenticate.__doc__ = function.__doc__
        return authenticate

    return wrapper

@authenticator
def basic(request, response, verify_user, **kwargs):
    """Basic HTTP Authentication"""
    http_auth = request.auth
    response.set_header('WWW-Authenticate', 'Basic')
    if http_auth is None:
        return

    if isinstance(http_auth, bytes):
        http_auth = http_auth.decode('utf8')
    try:
        auth_type, user_and_key = http_auth.split(' ', 1)
    except ValueError:
        raise HTTPUnauthorized('Authentication Error',
                               'Authentication header is improperly formed')

    if auth_type.lower() == 'basic':
        try:
            user_id, key = base64.decodebytes(bytes(user_and_key.strip(), 'utf8')).decode('utf8').split(':', 1)
            user = verify_user(user_id, key)
            if user:
                response.set_header('WWW-Authenticate', '')
                return user
        except (binascii.Error, ValueError):
            raise HTTPUnauthorized('Authentication Error',
                                   'Unable to determine user and password with provided encoding')
    return False

@authenticator
def api_key(request, response, verify_user, **kwargs):
    """API Key Header Authentication

    The verify_user function passed in to ths authenticator shall receive an
    API key as input, and return a user object to store in the request context
    if the request was successful.
    """
    api_key = request.get_header('X-Api-Key')

    if api_key:
        user = verify_user(api_key)
        if user:
            return user
        else:
            return False
    else:
        return None

@authenticator
def token(request, response, verify_user, **kwargs):
    """Token verification

     Checks for the Authorization header and verifies using the verify_user function
    """
    token = request.get_header('Authorization')
    if token:
        verified_token = verify_user(token)
        if verified_token:
            return verified_token
        else:
            return False
    return None

def verify(user, password):
    """Returns a simple verification callback that simply verifies that the users and password match that provided"""
    def verify_user(user_name, user_password):
        if user_name == user and user_password == password:
            return user_name
        return False
    return verify_user
<|endoftext|>


<commit_before>from jira import JIRA
from slackbot.bot import respond_to
import json
import dateutil.parser
import os
from slackbot.bot import listen_to
import re

credentials_id = '10004'
platform_audit_id = '10002'
platform_setup_id = '10003'
customer_voice_id = '10009'
photoshoot_id = '10007'
contact_id = '10201'
brand_kit_update_id = '10300'
gifted_photoshoot_id = '10800'
identity_refresh_id = '10802'
platform_refresh_id = '10801'
transition_photoshoot_ready = '121'
transition_credential_ready = '11'
transition_platform_audit_resolve = '61'
transition_credentials_resolve = '61'
transition_customer_voice_resolve = '61'
transition_platform_setup_resolve = '61'
transition_photoshoot_done = '11'
transition_contact_resolve = '31'
transition_followup_resolve = '31'
transition_brandkitupdate_resolve = '111'
salesforce_custom_field_id = 'customfield_10221'
resolution_id_customer_cancelled = '10200'
resolution_id_photoshoot_not_offered = '10400'
resolution_id_photoshoot_opted_out = '10100'
link_id_blocks = '10000'

@respond_to('jira onboard (.*)')
def jira_location(message, location_id):
    jira = authenticate()
    response = formatter.location_summary(get_all_onboard_issues(jira, location_id), "Location ID", location_id)
    message.reply_webapi('Onboard Summary', attachments=json.dumps(response))

@respond_to('jira jira (.*)')
def jira_location(message, location_id):
    jira = authenticate()
    response = formatter.location_summary(get_all_jira_issues(jira, location_id), "Location ID", location_id)
    message.reply_webapi('Location Summary', attachments=json.dumps(response))

@respond_to('jira sf (.*)')
def jira_location(message, sfid):
    jira = authenticate()
    response = formatter.location_summary(get_all_issues_salesforce_id(jira, sfid), "Salesforce ID", sfid)
    message.reply_webapi('Location Summary', attachments=json.dumps(response))

@respond_to('jira (PLATFORM\W[0-9]*|STUDIO\W[0-9]*)')
def jira_location(message, key):
    jira = authenticate()
    response = formatter.issue_summary(jira, key)
    message.reply_webapi('Issue Summary', attachments=json.dumps(response))

@respond_to('help')
def help(message):
    message.reply_webapi('Issue Summary', attachments= [{
        "fallback": "Ugh. I don't know what you are asking for. Try 'jira help'",
        "color": "ADD8E6",
        "title": "Commands you can use to get JIRA information:",
        "text": """*help:* Displays this message
*location <location id>:* Displays a summary of the 5 onboarding issues
*sf <salesforce id>:* Displays a summary of the 5 onboarding issues
*<issue key>:* Displays a summary of the input issue""",
        "mrkdwn_in": ["text", "pretext", "fields"],
    }])

def authenticate():
    return JIRA({'server': os.environ.get('JIRA_SERVER')},
                basic_auth=(os.environ.get('JIRA_USERNAME'), os.environ.get('JIRA_PASSWORD')))

def get_all_issues_salesforce_id(jira, sfid):
    issues = jira.search_issues(
        """project in (PLATFORM,STUDIO) AND 'Salesforce ID' ~ '%s'""" % sfid)
    return {str(issue.fields.issuetype.id): issue for issue in issues}

def get_all_onboard_issues(jira, location_id):
    issues = jira.search_issues("""project in (PLATFORM,STUDIO)
     AND issuetype in ('Platform Audit', Credentials, 'Platform Setup', 'Customer Voice', 'Photoshoot')
     AND 'Location ID' ~ %s""" % location_id)
    return {str(issue.fields.issuetype.id): issue for issue in issues}

def get_all_jira_issues(jira, location_id):
    issues = jira.search_issues("""project in (PLATFORM,STUDIO)
     AND 'Location ID' ~ %s ORDER BY created ASC""" % location_id)
    return {str(issue.fields.issuetype.id): issue for issue in issues}

class formatter:
    issue_url = """https://msh-success.atlassian.net/browse/%s"""

    @staticmethod
    def build_link(url, text):
        if formatter.should_jira_link():
            return "<%s|%s>" % (url, text)
        return text

    @staticmethod
    def should_jira_link():
        should_link = os.environ.get('CREATE_JIRA_LINKS')
        if should_link is not None and should_link == "YES":
            return True
        return False

    @staticmethod
    def get_issuetype(issue):
        return issue.fields.issuetype.name

    @staticmethod
    def get_issue_link(issue):
        if formatter.should_jira_link():
            return formatter.issue_url % issue.key
        return ""

    @staticmethod
    def get_date_time(field):
        if field is not None:
            return dateutil.parser.parse(field).strftime("%B %-d at %-I:%M %p")
        else:
            return "<none>"

    @staticmethod
    def get_assignee(issue):
        if issue.fields.assignee is None:
            return "Unassigned"
        else:
            return issue.fields.assignee.displayName

    @staticmethod
    def issue_summary(jira, key):
        issue = jira.issue(key)
        return [{
            "fallback": "Information for %s" % issue.fields.summary,
            "pretext": "Information for %s" % issue.fields.summary,
            "color": "#36a64f",
            "title": "%s: %s" % (formatter.get_issuetype(issue), issue.fields.summary),
            "title_link": formatter.get_issue_link(issue),
            "text": formatter.long_summary(issue),
            "mrkdwn_in": ["text", "pretext", "fields"],
            "thumb_url": issue.fields.issuetype.iconUrl,
            "footer": "Updated: %s" % formatter.get_date_time(issue.fields.updated)
        }]

    @staticmethod
    def long_summary(issue):
        str_list = []
        str_list.append(""">*Assignee: * %s\n""" % formatter.get_assignee(issue))
        str_list.append(""">*Status: * %s\n""" % issue.fields.status.name)
        str_list.append("""Last Updated: * %s\n""" % formatter.get_date_time(issue.fields.updated))

        if formatter.get_issuetype(issue) == "Platform Audit":
            str_list.append(""">*Offer Photoshoot:* %s\n""" % issue.fields.customfield_10212.value)
            str_list.append(""">*Facebook Presence:* %s\n""" % issue.fields.customfield_10502.value)
            str_list.append(""">*Twitter Presence:* %s\n""" % issue.fields.customfield_10505.value)
            str_list.append(""">*Google Presence:* %s\n""" % issue.fields.customfield_10508.value)
            str_list.append(""">*Foursquare Presence:* %s\n""" % issue.fields.customfield_10517.value)
        elif formatter.get_issuetype(issue) == "Photoshoot":
            str_list.append(
                ">*Photoshoot Date: * %s\n" % formatter.get_date_time(issue.fields.customfield_10205))
            str_list.append("""><%s|%s>""" % (issue.fields.customfield_10208, "Pixieset URL"))
        elif formatter.get_issuetype(issue) == "Customer Voice":
            str_list.append(""">*Approval Timestamp:* %s\n""" % formatter.get_date_time(issue.fields.customfield_11405))
            str_list.append("""><%s|%s>""" % (issue.fields.customfield_10210, "Passport URL"))
        return ''.join(str_list)

    @staticmethod
    def short_summary(issue):
        str_list = []
        str_list.append(""">*Status: * %s\n""" % formatter.build_link(formatter.get_issue_link(issue), issue.fields.status.name))
        str_list.append(""">*Updated: * %s\n""" % formatter.get_date_time(issue.fields.updated))
        str_list.append(""">*Assignee: * %s\n""" % formatter.get_assignee(issue))
        return ''.join(str_list)

    @staticmethod
    def search_results(issues):
        counter = 0;
        str_list = []
        name = ""
        for issue in issues:
            counter += 1
            if counter > 10:
                break;
            if issue.fields.issuetype.id == platform_audit_id:
                name = issue.fields.summary
            str_list.append("""%s %s: Created: %s\n""" % (issue.fields.status.name,
                                                      formatter.build_link(formatter.get_issue_link(issue), issue.key),
                                                      formatter.get_date_time(issue.fields.created))

        return [{
            "fallback": "Results",
            "pretext": "Results",
            "color": "#36a64f",
            "title": "%s - %d issues" % (name, len(issues)),
            "text": ''.join(str_list),
            "mrkdwn_in": ["text", "pretext", "fields"]
        }]

    @staticmethod
    def location_summary(issues, field, id):
        if len(issues) == 0:
            return [{
                "fallback": "No information exists for %s %s" % (field, id),
                "pretext": ">No information exists for %s %s" % (field, id),
                "mrkdwn_in": ["pretext"],
            }]

        business_name = issues[platform_audit_id].fields.summary
        audit = issues[platform_audit_id]
        creds = issues[credentials_id]
        setup = issues[platform_setup_id]
        cv = issues[customer_voice_id]
        photo = issues[photoshoot_id]
        location_id = audit.fields.customfield_10203

        return [{
            "fallback": "Onboarding Information for %s" % business_name,
            "pretext": "Onboarding Information for %s, Location ID: %s" % (business_name, location_id),
            "color": "#36a64f",
            "title": business_name,
            "fields": [
                {
                    "title": "Platform Audit: %s" % audit.key,
                    "value": formatter.short_summary(audit),
                    "short": "true"
                },
                {
                    "title": "",
                    "value": "",
                    "short": "true"
                },
                {
                    "title": "Credentials: %s" % creds.key,
                    "value": formatter.short_summary(creds),
                    "short": "true"
                },
                {
                    "title": "Photoshoot: %s" % photo.key,
                    "value": formatter.short_summary(photo),
                    "short": "false"
                },
                {
                    "title": "Customer Voice: %s" % cv.key,
                    "value": formatter.short_summary(cv),
                    "short": "false"
                },
                {
                    "title": "Platform Setup: %s" % setup.key,
                    "value": formatter.short_summary(setup),
                    "short": "false"
                }
            ],
            "mrkdwn_in": ["text", "pretext", "fields"]
        }]<commit_msg>More issue details<commit_after>from jira import JIRA
from slackbot.bot import respond_to
import json
import dateutil.parser
import os
from slackbot.bot import listen_to
import re

credentials_id = '10004'
platform_audit_id = '10002'
platform_setup_id = '10003'
customer_voice_id = '10009'
photoshoot_id = '10007'
contact_id = '10201'
brand_kit_update_id = '10300'
gifted_photoshoot_id = '10800'
identity_refresh_id = '10802'
platform_refresh_id = '10801'
transition_photoshoot_ready = '121'
transition_credential_ready = '11'
transition_platform_audit_resolve = '61'
transition_credentials_resolve = '61'
transition_customer_voice_resolve = '61'
transition_platform_setup_resolve = '61'
transition_photoshoot_done = '11'
transition_contact_resolve = '31'
transition_followup_resolve = '31'
transition_brandkitupdate_resolve = '111'
salesforce_custom_field_id = 'customfield_10221'
resolution_id_customer_cancelled = '10200'
resolution_id_photoshoot_not_offered = '10400'
resolution_id_photoshoot_opted_out = '10100'
link_id_blocks = '10000'

@respond_to('jira onboard (.*)')
def jira_location(message, location_id):
    jira = authenticate()
    response = formatter.location_summary(get_all_onboard_issues(jira, location_id), "Location ID", location_id)
    message.reply_webapi('Onboard Summary', attachments=json.dumps(response))

@respond_to('jira location (.*)')
def jira_location(message, location_id):
    jira = authenticate()
    response = formatter.location_summary(get_all_jira_issues(jira, location_id), "Location ID", location_id)
    message.reply_webapi('Location Summary', attachments=json.dumps(response))

@respond_to('jira sf (.*)')
def jira_location(message, sfid):
    jira = authenticate()
    response = formatter.location_summary(get_all_issues_salesforce_id(jira, sfid), "Salesforce ID", sfid)
    message.reply_webapi('Location Summary', attachments=json.dumps(response))

@respond_to('jira (PLATFORM\W[0-9]*|STUDIO\W[0-9]*)')
def jira_location(message, key):
    jira = authenticate()
    response = formatter.issue_summary(jira, key)
    message.reply_webapi('Issue Summary', attachments=json.dumps(response))

@respond_to('help')
def help(message):
    message.reply_webapi('Issue Summary', attachments= [{
        "fallback": "Ugh. I don't know what you are asking for. Try 'jira help'",
        "color": "ADD8E6",
        "title": "Commands you can use to get JIRA information:",
        "text": """*help:* Displays this message
*location <location id>:* Displays a summary of the 5 onboarding issues
*sf <salesforce id>:* Displays a summary of the 5 onboarding issues
*<issue key>:* Displays a summary of the input issue""",
        "mrkdwn_in": ["text", "pretext", "fields"],
    }])

def authenticate():
    return JIRA({'server': os.environ.get('JIRA_SERVER')},
                basic_auth=(os.environ.get('JIRA_USERNAME'), os.environ.get('JIRA_PASSWORD')))

def get_all_issues_salesforce_id(jira, sfid):
    issues = jira.search_issues(
        """project in (PLATFORM,STUDIO) AND 'Salesforce ID' ~ '%s'""" % sfid)
    return {str(issue.fields.issuetype.id): issue for issue in issues}

def get_all_onboard_issues(jira, location_id):
    issues = jira.search_issues("""project in (PLATFORM,STUDIO)
     AND issuetype in ('Platform Audit', Credentials, 'Platform Setup', 'Customer Voice', 'Photoshoot')
     AND 'Location ID' ~ %s""" % location_id)
    return {str(issue.fields.issuetype.id): issue for issue in issues}

def get_all_jira_issues(jira, location_id):
    issues = jira.search_issues("""project in (PLATFORM,STUDIO)
     AND 'Location ID' ~ %s ORDER BY created ASC""" % location_id)
    return {str(issue.fields.issuetype.id): issue for issue in issues}

class formatter:
    issue_url = """https://msh-success.atlassian.net/browse/%s"""

    @staticmethod
    def build_link(url, text):
        if formatter.should_jira_link():
            return "<%s|%s>" % (url, text)
        return text

    @staticmethod
    def should_jira_link():
        should_link = os.environ.get('CREATE_JIRA_LINKS')
        if should_link is not None and should_link == "YES":
            return True
        return False

    @staticmethod
    def get_issuetype(issue):
        return issue.fields.issuetype.name

    @staticmethod
    def get_issue_link(issue):
        if formatter.should_jira_link():
            return formatter.issue_url % issue.key
        return ""

    @staticmethod
    def get_date_time(field):
        if field is not None:
            return dateutil.parser.parse(field).strftime("%B %-d at %-I:%M %p")
        else:
            return "<none>"

    @staticmethod
    def get_assignee(issue):
        if issue.fields.assignee is None:
            return "Unassigned"
        else:
            return issue.fields.assignee.displayName

    @staticmethod
    def issue_summary(jira, key):
        issue = jira.issue(key)
        return [{
            "fallback": "Information for %s" % issue.fields.summary,
            "pretext": "Information for %s" % issue.fields.summary,
            "color": "#36a64f",
            "title": "%s: %s" % (formatter.get_issuetype(issue), issue.fields.summary),
            "title_link": formatter.get_issue_link(issue),
            "text": formatter.long_summary(issue),
            "mrkdwn_in": ["text", "pretext", "fields"],
            "thumb_url": issue.fields.issuetype.iconUrl,
            "footer": "Updated: %s" % formatter.get_date_time(issue.fields.updated)
        }]

    @staticmethod
    def long_summary(issue):
        str_list = []
        str_list.append(""">*Assignee: * %s\n""" % formatter.get_assignee(issue))
        str_list.append(""">*Status: * %s\n""" % issue.fields.status.name)
        str_list.append("""Last Updated: * %s\n""" % formatter.get_date_time(issue.fields.updated))

        if formatter.get_issuetype(issue) == "Platform Audit":
            str_list.append(""">*Offer Photoshoot:* %s\n""" % issue.fields.customfield_10212.value)
            str_list.append(""">*Facebook Presence:* %s\n""" % issue.fields.customfield_10502.value)
            str_list.append(""">*Twitter Presence:* %s\n""" % issue.fields.customfield_10505.value)
            str_list.append(""">*Google Presence:* %s\n""" % issue.fields.customfield_10508.value)
            str_list.append(""">*Foursquare Presence:* %s\n""" % issue.fields.customfield_10517.value)
        elif formatter.get_issuetype(issue) == "Photoshoot":
            str_list.append(
                ">*Photoshoot Date: * %s\n" % formatter.get_date_time(issue.fields.customfield_10205))
            str_list.append("""><%s|%s>""" % (issue.fields.customfield_10208, "Pixieset URL"))
        elif formatter.get_issuetype(issue) == "Customer Voice":
            str_list.append(""">*Approval Timestamp:* %s\n""" % formatter.get_date_time(issue.fields.customfield_11405))
            str_list.append("""><%s|%s>""" % (issue.fields.customfield_10210, "Passport URL"))
        return ''.join(str_list)

    @staticmethod
    def short_summary(issue):
        str_list = []
        str_list.append(""">*Status: * %s\n""" % formatter.build_link(formatter.get_issue_link(issue), issue.fields.status.name))
        str_list.append(""">*Updated: * %s\n""" % formatter.get_date_time(issue.fields.updated))
        str_list.append(""">*Assignee: * %s\n""" % formatter.get_assignee(issue))
        return ''.join(str_list)

    @staticmethod
    def search_results(issues):
        counter = 0;
        str_list = []
        name = ""
        for issue in issues:
            counter += 1
            if counter > 10:
                break;
            if issue.fields.issuetype.id == platform_audit_id:
                name = issue.fields.summary
            str_list.append("""%s %s: Created: %s\n""" % (issue.fields.status.name,
                                                      formatter.build_link(formatter.get_issue_link(issue), issue.key),
                                                      formatter.get_date_time(issue.fields.created))

        return [{
            "fallback": "Results",
            "pretext": "Results",
            "color": "#36a64f",
            "title": "%s - %d issues" % (name, len(issues)),
            "text": ''.join(str_list),
            "mrkdwn_in": ["text", "pretext", "fields"]
        }]

    @staticmethod
    def location_summary(issues, field, id):
        if len(issues) == 0:
            return [{
                "fallback": "No information exists for %s %s" % (field, id),
                "pretext": ">No information exists for %s %s" % (field, id),
                "mrkdwn_in": ["pretext"],
            }]

        business_name = issues[platform_audit_id].fields.summary
        audit = issues[platform_audit_id]
        creds = issues[credentials_id]
        setup = issues[platform_setup_id]
        cv = issues[customer_voice_id]
        photo = issues[photoshoot_id]
        location_id = audit.fields.customfield_10203

        return [{
            "fallback": "Onboarding Information for %s" % business_name,
            "pretext": "Onboarding Information for %s, Location ID: %s" % (business_name, location_id),
            "color": "#36a64f",
            "title": business_name,
            "fields": [
                {
                    "title": "Platform Audit: %s" % audit.key,
                    "value": formatter.short_summary(audit),
                    "short": "true"
                },
                {
                    "title": "",
                    "value": "",
                    "short": "true"
                },
                {
                    "title": "Credentials: %s" % creds.key,
                    "value": formatter.short_summary(creds),
                    "short": "true"
                },
                {
                    "title": "Photoshoot: %s" % photo.key,
                    "value": formatter.short_summary(photo),
                    "short": "false"
                },
                {
                    "title": "Customer Voice: %s" % cv.key,
                    "value": formatter.short_summary(cv),
                    "short": "false"
                },
                {
                    "title": "Platform Setup: %s" % setup.key,
                    "value": formatter.short_summary(setup),
                    "short": "false"
                }
            ],
            "mrkdwn_in": ["text", "pretext", "fields"]
        }]<|endoftext|>