<commit_before>__all__ = ['threshold_adaptive',
           'threshold_otsu',
           'threshold_yen',
           'threshold_isodata',
           'threshold_li', ]

import numpy as np
from scipy import ndimage as ndi
from ..exposure import histogram
from .._shared.utils import assert_nD, warn

def threshold_adaptive(image, block_size, method='gaussian', offset=0,
                       mode='reflect', param=None):
    """Applies an adaptive threshold to an array.

    Also known as local or dynamic thresholding where the threshold value is
    the weighted mean for the local neighborhood of a pixel subtracted by a
    constant. Alternatively the threshold can be determined dynamically by a a
    given function using the 'generic' method.

    Parameters
    ----------
    image : (N, M) ndarray
        Input image.
    block_size : int
        Odd size of pixel neighborhood which is used to calculate the
        threshold value (e.g. 3, 5, 7, ..., 21, ...).
    method : {'generic', 'gaussian', 'mean', 'median'}, optional
        Method used to determine adaptive threshold for local neighbourhood in
        weighted mean image.

        * 'generic': use custom function (see `param` parameter)
        * 'gaussian': apply gaussian filter (see `param` parameter for custom\
                      sigma value)
        * 'mean': apply arithmetic mean filter
        * 'median': apply median rank filter

        By default the 'gaussian' method is used.
    offset : float, optional
        Constant subtracted from weighted mean of neighborhood to calculate
        the local threshold value. Default offset is 0.
    mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
        The mode parameter determines how the array borders are handled, where
        cval is the value when mode is equal to 'constant'.
        Default is 'reflect'.
    param : {int, function}, optional
        Either specify sigma for 'gaussian' method or function object for
        'generic' method. This functions takes the flat array of local
        neighbourhood as a single argument and returns the calculated
        threshold for the centre pixel.

    Returns
    -------
    threshold : (N, M) ndarray
        Thresholded binary image

    References
    ----------
    .. [1] http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html?highlight=threshold#adaptivethreshold

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()[:50, :50]
    >>> binary_image1 = threshold_adaptive(image, 15, 'mean')
    >>> func = lambda arr: arr.mean()
    >>> binary_image2 = threshold_adaptive(image, 15, 'generic', param=func)
    """
    if block_size % 2 == 0:
        raise ValueError("The kwarg ``block_size`` must be odd! Given "
                         "``block_size`` {0} is even.".format(block_size))
    assert_nD(image, 2)
    thresh_image = np.zeros(image.shape, 'double')
    if method == 'generic':
        ndi.generic_filter(image, param, block_size,
                           output=thresh_image, mode=mode)
    elif method == 'gaussian':
        if param is None:
            # automatically determine sigma which covers > 99% of distribution
            sigma = (block_size - 1) / 6.0
        else:
            sigma = param
        ndi.gaussian_filter(image, sigma, output=thresh_image, mode=mode)
    elif method == 'mean':
        mask = 1. / block_size * np.ones((block_size,))
        # separation of filters to speedup convolution
        ndi.convolve1d(image, mask, axis=0, output=thresh_image, mode=mode)
        ndi.convolve1d(thresh_image, mask, axis=1,
                       output=thresh_image, mode=mode)
    elif method == 'median':
        ndi.median_filter(image, block_size, output=thresh_image, mode=mode)

    return image > (thresh_image - offset)

def threshold_otsu(image, nbins=256):
    """Return threshold value based on Otsu's method.

    Parameters
    ----------
    image : array
        Grayscale input image.
    nbins : int, optional
        Number of bins used to calculate histogram. This value is ignored for
        integer arrays.

    Returns
    -------
    threshold : float
        Upper threshold value. All pixels intensities that less or equal of
        this value assumed as foreground.

    References
    ----------
    .. [1] Wikipedia, http://en.wikipedia.org/wiki/Otsu's_Method

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()
    >>> thresh = threshold_otsu(image)
    >>> binary = image <= thresh

    Notes
    -----
    The input image must be grayscale.
    """
    if image.shape[-1] in (3, 4):
        msg = "threshold_otsu is expected to work correctly only for " \
              "grayscale images; image shape {0} looks like an RGB image"
        warn(msg.format(image.shape))

    # Check if the image is multi-colored or not
    if image.min() == image.max():
        raise ValueError("threshold_otsu is expected to work with images " \
                         "having more than one color. The input image seems " \
                         "to have just one color {0}.".format(image.min()))

    hist, bin_centers = histogram(image.ravel(), nbins)
    hist = hist.astype(float)

    # class probabilities for all possible thresholds
    weight1 = np.cumsum(hist)
    weight2 = np.cumsum(hist[::-1])[::-1]
    # class means for all possible thresholds
    mean1 = np.cumsum(hist * bin_centers) / weight1
    mean2 = (np.cumsum((hist * bin_centers)[::-1]) / weight2[::-1])[::-1]

    # Clip ends to align class 1 and class 2 variables:
    # The last value of `weight1`/`mean1` should pair with zero values in
    # `weight2`/`mean2`, which do not exist.
    variance12 = weight1[:-1] * weight2[1:] * (mean1[:-1] - mean2[1:]) ** 2

    idx = np.argmax(variance12)
    threshold = bin_centers[:-1][idx]
    return threshold

def threshold_yen(image, nbins=256):
    """Return threshold value based on Yen's method.

    Parameters
    ----------
    image : array
        Input image.
    nbins : int, optional
        Number of bins used to calculate histogram. This value is ignored for
        integer arrays.

    Returns
    -------
    threshold : float
        Upper threshold value. All pixels intensities that less or equal of
        this value assumed as foreground.

    References
    ----------
    .. [1] Yen J.C., Chang F.J., and Chang S. (1995) "A New Criterion
           for Automatic Multilevel Thresholding" IEEE Trans. on Image
           Processing, 4(3): 370-378
    .. [2] Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
           Techniques and Quantitative Performance Evaluation" Journal of
           Electronic Imaging, 13(1): 146-165,
           http://www.busim.ee.boun.edu.tr/~sankur/SankurFolder/Threshold_survey.pdf
    .. [3] ImageJ AutoThresholder code, http://fiji.sc/wiki/index.php/Auto_Threshold

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()
    >>> thresh = threshold_yen(image)
    >>> binary = image <= thresh
    """
    hist, bin_centers = histogram(image.ravel(), nbins)
    # On blank images (e.g. filled with 0) with int dtype, `histogram()`
    # returns `bin_centers` containing only one value. Speed up with it.
    if bin_centers.size == 1:
        return bin_centers[0]

    # Calculate probability mass function
    pmf = hist.astype(np.float32) / hist.sum()
    P1 = np.cumsum(pmf)  # Cumulative normalized histogram
    P1_sq = np.cumsum(pmf ** 2)
    # Get cumsum calculated from end of squared array:
    P2_sq = np.cumsum(pmf[::-1] ** 2)[::-1]
    # P2_sq indexes is shifted +1. I assume, with P1[:-1] it's help avoid '-inf'
    # in crit. ImageJ Yen implementation replaces those values by zero.
    crit = np.log(((P1_sq[:-1] * P2_sq[1:]) ** -1) *
                  (P1[:-1] * (1.0 - P1[:-1])) ** 2)
    return bin_centers[crit.argmax()]

def threshold_isodata(image, nbins=256, return_all=False):
    """Return threshold value(s) based on ISODATA method.

    Histogram-based threshold, known as Ridler-Calvard method or inter-means.
    Threshold values returned satisfy the following equality:

    `threshold = (image[image <= threshold].mean() +`
                 `image[image > threshold].mean()) / 2.0`

    That is, returned thresholds are intensities that separate the image into
    two groups of pixels, where the threshold intensity is midway between the
    mean intensities of these groups.

    For integer images, the above equality holds to within one; for floating-
    point images, the equality holds to within the histogram bin-width.

    Parameters
    ----------
    image : array
        Input image.
    nbins : int, optional
        Number of bins used to calculate histogram. This value is ignored for
        integer arrays.
    return_all: bool, optional
        If False (default), return only the lowest threshold that satisfies
        the above equality. If True, return all valid thresholds.

    Returns
    -------
    threshold : float or int or array
        Threshold value(s).

    References
    ----------
    .. [1] Ridler, TW & Calvard, S (1978), "Picture thresholding using an
           iterative selection method"
    .. [2] IEEE Transactions on Systems, Man and Cybernetics 8: 630-632,
           http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=4310039
    .. [3] Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
           Techniques and Quantitative Performance Evaluation" Journal of
           Electronic Imaging, 13(1): 146-165,
           http://www.busim.ee.boun.edu.tr/~sankur/SankurFolder/Threshold_survey.pdf
    .. [4] ImageJ AutoThresholder code,
           http://fiji.sc/wiki/index.php/Auto_Threshold

    Examples
    --------
    >>> from skimage.data import coins
    >>> image = coins()
    >>> thresh = threshold_isodata(image)
    >>> binary = image > thresh
    """
    hist, bin_centers = histogram(image.ravel(), nbins)

    # image only contains one unique value
    if len(bin_centers) == 1:
        if return_all:
            return bin_centers
        else:
            return bin_centers[0]

    hist = hist.astype(np.float32)

    # csuml and csumh contain the count of pixels in that bin or lower, and
    # in all bins strictly higher than that bin, respectively
    csuml = np.cumsum(hist)
    csumh = np.cumsum(hist[::-1])[::-1] - hist

    # intensity_sum contains the total pixel intensity from each bin
    intensity_sum = hist * bin_centers

    # l and h contain average value of all pixels in that bin or lower, and
    # in all bins strictly higher than that bin, respectively.
    # Note that since exp.histogram does not include empty bins at the low or
    # high end of the range, csuml and csumh are strictly > 0, except in the
    # last bin of csumh, which is zero by construction.
    # So no worries about division by zero in the following lines, except
    # for the last bin, but we can ignore that because no valid threshold
    # can be in the top bin. So we just patch up csumh[-1] to not cause 0/0
    # errors.
    csumh[-1] = 1
    l = np.cumsum(intensity_sum) / csuml
    h = (np.cumsum(intensity_sum[::-1])[::-1] - intensity_sum) / csumh

    # isodata finds threshold values that meet the criterion t = (l + m)/2
    # where l is the mean of all pixels <= t and h is the mean of all pixels
    # > t, as calculated above. So we are looking for places where
    # (l + m) / 2 equals the intensity value for which those l and m figures
    # were calculated -- which is, of course, the histogram bin centers.
    # We only require this equality to be within the precision of the bin
    # width, of course.
    all_mean = (l + h) / 2.0
    bin_width = bin_centers[1] - bin_centers[0]

    # Look only at thresholds that are below the actual all_mean value,
    # for consistency with the threshold being included in the lower pixel
    # group. Otherwise can get thresholds that are not actually fixed-points
    # of the isodata algorithm. For float images, this matters less, since
    # there really can't be any guarantees anymore anyway.
    distances = all_mean - bin_centers
    thresholds = bin_centers[(distances >= 0) & (distances < bin_width)]

    if return_all:
        return thresholds
    else:
        return thresholds[0]

def threshold_li(image):
    """Return threshold value based on adaptation of Li's Minimum Cross Entropy method.

    Parameters
    ----------
    image : array
        Input image.

    Returns
    -------
    threshold : float
        Upper threshold value. All pixels intensities more than
        this value are assumed to be foreground.

    References
    ----------
    .. [1] Li C.H. and Lee C.K. (1993) "Minimum Cross Entropy Thresholding"
           Pattern Recognition, 26(4): 617-625
    .. [2] Li C.H. and Tam P.K.S. (1998) "An Iterative Algorithm for Minimum
           Cross Entropy Thresholding" Pattern Recognition Letters, 18(8): 771-776
    .. [3] Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
           Techniques and Quantitative Performance Evaluation" Journal of
           Electronic Imaging, 13(1): 146-165
           http://citeseer.ist.psu.edu/sezgin04survey.html
    .. [4] ImageJ AutoThresholder code, http://fiji.sc/wiki/index.php/Auto_Threshold

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()
    >>> thresh = threshold_li(image)
    >>> binary = image > thresh
    """
    # Copy to ensure input image is not modified
    image = image.copy()
    # Requires positive image (because of log(mean))
    immin = np.min(image)
    image -= immin
    imrange = np.max(image)
    tolerance = 0.5 * imrange / 256

    # Calculate the mean gray-level
    mean = np.mean(image)

    # Initial estimate
    new_thresh = mean
    old_thresh = new_thresh + 2 * tolerance

    # Stop the iterations when the difference between the
    # new and old threshold values is less than the tolerance
    while abs(new_thresh - old_thresh) > tolerance:
        old_thresh = new_thresh
        threshold = old_thresh + tolerance   # range
        # Calculate the means of background and object pixels
        mean_back = image[image <= threshold].mean()
        mean_obj = image[image > threshold].mean()

        temp = (mean_back - mean_obj) / (np.log(mean_back) - np.log(mean_obj))

        if temp < 0:
            new_thresh = temp - tolerance
        else:
            new_thresh = temp + tolerance

    return threshold + immin
<commit_msg>Added missing documentation about raised error<commit_after>__all__ = ['threshold_adaptive',
           'threshold_otsu',
           'threshold_yen',
           'threshold_isodata',
           'threshold_li', ]

import numpy as np
from scipy import ndimage as ndi
from ..exposure import histogram
from .._shared.utils import assert_nD, warn

def threshold_adaptive(image, block_size, method='gaussian', offset=0,
                       mode='reflect', param=None):
    """Applies an adaptive threshold to an array.

    Also known as local or dynamic thresholding where the threshold value is
    the weighted mean for the local neighborhood of a pixel subtracted by a
    constant. Alternatively the threshold can be determined dynamically by a a
    given function using the 'generic' method.

    Parameters
    ----------
    image : (N, M) ndarray
        Input image.
    block_size : int
        Odd size of pixel neighborhood which is used to calculate the
        threshold value (e.g. 3, 5, 7, ..., 21, ...).
    method : {'generic', 'gaussian', 'mean', 'median'}, optional
        Method used to determine adaptive threshold for local neighbourhood in
        weighted mean image.

        * 'generic': use custom function (see `param` parameter)
        * 'gaussian': apply gaussian filter (see `param` parameter for custom\
                      sigma value)
        * 'mean': apply arithmetic mean filter
        * 'median': apply median rank filter

        By default the 'gaussian' method is used.
    offset : float, optional
        Constant subtracted from weighted mean of neighborhood to calculate
        the local threshold value. Default offset is 0.
    mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
        The mode parameter determines how the array borders are handled, where
        cval is the value when mode is equal to 'constant'.
        Default is 'reflect'.
    param : {int, function}, optional
        Either specify sigma for 'gaussian' method or function object for
        'generic' method. This functions takes the flat array of local
        neighbourhood as a single argument and returns the calculated
        threshold for the centre pixel.

    Returns
    -------
    threshold : (N, M) ndarray
        Thresholded binary image

    References
    ----------
    .. [1] http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html?highlight=threshold#adaptivethreshold

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()[:50, :50]
    >>> binary_image1 = threshold_adaptive(image, 15, 'mean')
    >>> func = lambda arr: arr.mean()
    >>> binary_image2 = threshold_adaptive(image, 15, 'generic', param=func)
    """
    if block_size % 2 == 0:
        raise ValueError("The kwarg ``block_size`` must be odd! Given "
                         "``block_size`` {0} is even.".format(block_size))
    assert_nD(image, 2)
    thresh_image = np.zeros(image.shape, 'double')
    if method == 'generic':
        ndi.generic_filter(image, param, block_size,
                           output=thresh_image, mode=mode)
    elif method == 'gaussian':
        if param is None:
            # automatically determine sigma which covers > 99% of distribution
            sigma = (block_size - 1) / 6.0
        else:
            sigma = param
        ndi.gaussian_filter(image, sigma, output=thresh_image, mode=mode)
    elif method == 'mean':
        mask = 1. / block_size * np.ones((block_size,))
        # separation of filters to speedup convolution
        ndi.convolve1d(image, mask, axis=0, output=thresh_image, mode=mode)
        ndi.convolve1d(thresh_image, mask, axis=1,
                       output=thresh_image, mode=mode)
    elif method == 'median':
        ndi.median_filter(image, block_size, output=thresh_image, mode=mode)

    return image > (thresh_image - offset)

def threshold_otsu(image, nbins=256):
    """Return threshold value based on Otsu's method.

    Parameters
    ----------
    image : array
        Grayscale input image.
    nbins : int, optional
        Number of bins used to calculate histogram. This value is ignored for
        integer arrays.

    Returns
    -------
    threshold : float
        Upper threshold value. All pixels intensities that less or equal of
        this value assumed as foreground.

    Raises
    ------

    ValueError
         If `image` only contains a single grayscale value.

    References
    ----------
    .. [1] Wikipedia, http://en.wikipedia.org/wiki/Otsu's_Method

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()
    >>> thresh = threshold_otsu(image)
    >>> binary = image <= thresh

    Notes
    -----
    The input image must be grayscale.
    """
    if image.shape[-1] in (3, 4):
        msg = "threshold_otsu is expected to work correctly only for " \
              "grayscale images; image shape {0} looks like an RGB image"
        warn(msg.format(image.shape))

    # Check if the image is multi-colored or not
    if image.min() == image.max():
        raise ValueError("threshold_otsu is expected to work with images " \
                         "having more than one color. The input image seems " \
                         "to have just one color {0}.".format(image.min()))

    hist, bin_centers = histogram(image.ravel(), nbins)
    hist = hist.astype(float)

    # class probabilities for all possible thresholds
    weight1 = np.cumsum(hist)
    weight2 = np.cumsum(hist[::-1])[::-1]
    # class means for all possible thresholds
    mean1 = np.cumsum(hist * bin_centers) / weight1
    mean2 = (np.cumsum((hist * bin_centers)[::-1]) / weight2[::-1])[::-1]

    # Clip ends to align class 1 and class 2 variables:
    # The last value of `weight1`/`mean1` should pair with zero values in
    # `weight2`/`mean2`, which do not exist.
    variance12 = weight1[:-1] * weight2[1:] * (mean1[:-1] - mean2[1:]) ** 2

    idx = np.argmax(variance12)
    threshold = bin_centers[:-1][idx]
    return threshold

def threshold_yen(image, nbins=256):
    """Return threshold value based on Yen's method.

    Parameters
    ----------
    image : array
        Input image.
    nbins : int, optional
        Number of bins used to calculate histogram. This value is ignored for
        integer arrays.

    Returns
    -------
    threshold : float
        Upper threshold value. All pixels intensities that less or equal of
        this value assumed as foreground.

    References
    ----------
    .. [1] Yen J.C., Chang F.J., and Chang S. (1995) "A New Criterion
           for Automatic Multilevel Thresholding" IEEE Trans. on Image
           Processing, 4(3): 370-378
    .. [2] Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
           Techniques and Quantitative Performance Evaluation" Journal of
           Electronic Imaging, 13(1): 146-165,
           http://www.busim.ee.boun.edu.tr/~sankur/SankurFolder/Threshold_survey.pdf
    .. [3] ImageJ AutoThresholder code, http://fiji.sc/wiki/index.php/Auto_Threshold

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()
    >>> thresh = threshold_yen(image)
    >>> binary = image <= thresh
    """
    hist, bin_centers = histogram(image.ravel(), nbins)
    # On blank images (e.g. filled with 0) with int dtype, `histogram()`
    # returns `bin_centers` containing only one value. Speed up with it.
    if bin_centers.size == 1:
        return bin_centers[0]

    # Calculate probability mass function
    pmf = hist.astype(np.float32) / hist.sum()
    P1 = np.cumsum(pmf)  # Cumulative normalized histogram
    P1_sq = np.cumsum(pmf ** 2)
    # Get cumsum calculated from end of squared array:
    P2_sq = np.cumsum(pmf[::-1] ** 2)[::-1]
    # P2_sq indexes is shifted +1. I assume, with P1[:-1] it's help avoid '-inf'
    # in crit. ImageJ Yen implementation replaces those values by zero.
    crit = np.log(((P1_sq[:-1] * P2_sq[1:]) ** -1) *
                  (P1[:-1] * (1.0 - P1[:-1])) ** 2)
    return bin_centers[crit.argmax()]

def threshold_isodata(image, nbins=256, return_all=False):
    """Return threshold value(s) based on ISODATA method.

    Histogram-based threshold, known as Ridler-Calvard method or inter-means.
    Threshold values returned satisfy the following equality:

    `threshold = (image[image <= threshold].mean() +`
                 `image[image > threshold].mean()) / 2.0`

    That is, returned thresholds are intensities that separate the image into
    two groups of pixels, where the threshold intensity is midway between the
    mean intensities of these groups.

    For integer images, the above equality holds to within one; for floating-
    point images, the equality holds to within the histogram bin-width.

    Parameters
    ----------
    image : array
        Input image.
    nbins : int, optional
        Number of bins used to calculate histogram. This value is ignored for
        integer arrays.
    return_all: bool, optional
        If False (default), return only the lowest threshold that satisfies
        the above equality. If True, return all valid thresholds.

    Returns
    -------
    threshold : float or int or array
        Threshold value(s).

    References
    ----------
    .. [1] Ridler, TW & Calvard, S (1978), "Picture thresholding using an
           iterative selection method"
    .. [2] IEEE Transactions on Systems, Man and Cybernetics 8: 630-632,
           http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=4310039
    .. [3] Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
           Techniques and Quantitative Performance Evaluation" Journal of
           Electronic Imaging, 13(1): 146-165,
           http://www.busim.ee.boun.edu.tr/~sankur/SankurFolder/Threshold_survey.pdf
    .. [4] ImageJ AutoThresholder code,
           http://fiji.sc/wiki/index.php/Auto_Threshold

    Examples
    --------
    >>> from skimage.data import coins
    >>> image = coins()
    >>> thresh = threshold_isodata(image)
    >>> binary = image > thresh
    """
    hist, bin_centers = histogram(image.ravel(), nbins)

    # image only contains one unique value
    if len(bin_centers) == 1:
        if return_all:
            return bin_centers
        else:
            return bin_centers[0]

    hist = hist.astype(np.float32)

    # csuml and csumh contain the count of pixels in that bin or lower, and
    # in all bins strictly higher than that bin, respectively
    csuml = np.cumsum(hist)
    csumh = np.cumsum(hist[::-1])[::-1] - hist

    # intensity_sum contains the total pixel intensity from each bin
    intensity_sum = hist * bin_centers

    # l and h contain average value of all pixels in that bin or lower, and
    # in all bins strictly higher than that bin, respectively.
    # Note that since exp.histogram does not include empty bins at the low or
    # high end of the range, csuml and csumh are strictly > 0, except in the
    # last bin of csumh, which is zero by construction.
    # So no worries about division by zero in the following lines, except
    # for the last bin, but we can ignore that because no valid threshold
    # can be in the top bin. So we just patch up csumh[-1] to not cause 0/0
    # errors.
    csumh[-1] = 1
    l = np.cumsum(intensity_sum) / csuml
    h = (np.cumsum(intensity_sum[::-1])[::-1] - intensity_sum) / csumh

    # isodata finds threshold values that meet the criterion t = (l + m)/2
    # where l is the mean of all pixels <= t and h is the mean of all pixels
    # > t, as calculated above. So we are looking for places where
    # (l + m) / 2 equals the intensity value for which those l and m figures
    # were calculated -- which is, of course, the histogram bin centers.
    # We only require this equality to be within the precision of the bin
    # width, of course.
    all_mean = (l + h) / 2.0
    bin_width = bin_centers[1] - bin_centers[0]

    # Look only at thresholds that are below the actual all_mean value,
    # for consistency with the threshold being included in the lower pixel
    # group. Otherwise can get thresholds that are not actually fixed-points
    # of the isodata algorithm. For float images, this matters less, since
    # there really can't be any guarantees anymore anyway.
    distances = all_mean - bin_centers
    thresholds = bin_centers[(distances >= 0) & (distances < bin_width)]

    if return_all:
        return thresholds
    else:
        return thresholds[0]

def threshold_li(image):
    """Return threshold value based on adaptation of Li's Minimum Cross Entropy method.

    Parameters
    ----------
    image : array
        Input image.

    Returns
    -------
    threshold : float
        Upper threshold value. All pixels intensities more than
        this value are assumed to be foreground.

    References
    ----------
    .. [1] Li C.H. and Lee C.K. (1993) "Minimum Cross Entropy Thresholding"
           Pattern Recognition, 26(4): 617-625
    .. [2] Li C.H. and Tam P.K.S. (1998) "An Iterative Algorithm for Minimum
           Cross Entropy Thresholding" Pattern Recognition Letters, 18(8): 771-776
    .. [3] Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
           Techniques and Quantitative Performance Evaluation" Journal of
           Electronic Imaging, 13(1): 146-165
           http://citeseer.ist.psu.edu/sezgin04survey.html
    .. [4] ImageJ AutoThresholder code, http://fiji.sc/wiki/index.php/Auto_Threshold

    Examples
    --------
    >>> from skimage.data import camera
    >>> image = camera()
    >>> thresh = threshold_li(image)
    >>> binary = image > thresh
    """
    # Copy to ensure input image is not modified
    image = image.copy()
    # Requires positive image (because of log(mean))
    immin = np.min(image)
    image -= immin
    imrange = np.max(image)
    tolerance = 0.5 * imrange / 256

    # Calculate the mean gray-level
    mean = np.mean(image)

    # Initial estimate
    new_thresh = mean
    old_thresh = new_thresh + 2 * tolerance

    # Stop the iterations when the difference between the
    # new and old threshold values is less than the tolerance
    while abs(new_thresh - old_thresh) > tolerance:
        old_thresh = new_thresh
        threshold = old_thresh + tolerance   # range
        # Calculate the means of background and object pixels
        mean_back = image[image <= threshold].mean()
        mean_obj = image[image > threshold].mean()

        temp = (mean_back - mean_obj) / (np.log(mean_back) - np.log(mean_obj))

        if temp < 0:
            new_thresh = temp - tolerance
        else:
            new_thresh = temp + tolerance

    return threshold + immin
<|endoftext|>


<commit_before>#
# Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
#

#
# Sandesh Http
#

import pkgutil
import importlib
import sys
#
# Prevent:
# Exception KeyError: KeyError(40918224,) in <module 'threading' from '/usr/lib64/python2.7/threading.pyc'> ignored
# as per
# http://stackoverflow.com/questions/8774958/keyerror-in-module-threading-after-a-successful-py-test-run
#
if 'threading' in sys.modules:
    del sys.modules['threading']
from gevent import monkey; monkey.patch_all()
import wsgiref
from wsgiref.simple_server import make_server
import bottle
import cStringIO
from transport import TTransport
from protocol import TXMLProtocol
import os
import socket

class SandeshHttp(object):

    _HTTP_SERVER_IP = '0.0.0.0'
    _http_response = None
    _http_response_context = None
    _logger = None

    WebFilesList = [
    '/css/bootstrap.min.css',
    '/css/DT_bootstrap.css',
    '/css/images/sort_asc.png',
    '/css/images/sort_asc_disabled.png',
    '/css/images/sort_both.png',
    '/css/images/sort_desc.png',
    '/css/images/sort_desc_disabled.png',
    '/css/style.css',
    '/js/bootstrap.min.js',
    '/js/DT_bootstrap.js',
    '/js/jquery-2.0.3.min.js',
    '/js/jquery.dataTables.min.js',
    '/js/util.js',
    '/universal_parse.xsl']

    def __init__(self, sandesh, module, port, pkg_list):
        self._sandesh = sandesh
        self._logger = sandesh.logger()
        self._module = module
        self._http_port = port
        self._http_request_dict = {}
        self._http_app = bottle.Bottle()
        self._create_homepage(pkg_list)
        # Register the homepage
        self._http_app.route('/', 'GET', self._get_homepage)
        self._http_app.route('/index.html', 'GET', self._get_homepage)
        self._http_app.route('/<link:re:\w+.xml>', 'GET', self._get_indexpage)
        # Get the path of universal_parse.xsl and jquery and register the same
        self._webfiles_path = None
        self._universal_parse_xsl_path = None
        self._jquery_collapse_storage_js_path = None
        self._jquery_collapse_js_path = None
        self._jquery_1_8_1_js_path = None
        try:
            imp_pysandesh = __import__('pysandesh')
        except ImportError:
            self._logger.error('Failed to import "pysandesh"')
        else:
            self._webfiles_path = imp_pysandesh.__path__[0]
            self._universal_parse_xsl_path = imp_pysandesh.__path__[0]
            self._jquery_collapse_storage_js_path = imp_pysandesh.__path__[0]
            self._jquery_collapse_js_path = imp_pysandesh.__path__[0]
            self._jquery_1_8_1_js_path = imp_pysandesh.__path__[0]

        for elem in SandeshHttp.WebFilesList:
            #import pdb; pdb.set_trace()
            self._http_app.route(elem, 'GET', self._get_webfiles)

    #end __init__

    def start_http_server(self):
        try:
            svr = make_server(SandeshHttp._HTTP_SERVER_IP, self._http_port,
                              self._http_app)
        except socket.error as e:
            self._logger.error('Unable to open HTTP Port %d, %s' % (self._http_port, e))
            sys.exit()
        self._http_port = svr.server_port
        self._logger.error('Starting Introspect on HTTP Port %d' % self._http_port)
        self._sandesh.record_port("http", self._http_port)
        svr.serve_forever()

    #end start_http_server

    def get_port(self):
        return self._http_port
    #end get_port

    @staticmethod
    def http_error(err_msg):
        return '
%s
' % (err_msg)
    #end http_error

    @staticmethod
    def create_http_response(sandesh_resp, sandesh_init):
        universal_xsl_str = '<?xml-stylesheet type="text/xsl" href="/universal_parse.xsl"?>'
        transport = TTransport.TMemoryBuffer()
        protocol_factory = TXMLProtocol.TXMLProtocolFactory()
        protocol = protocol_factory.getProtocol(transport)
        if sandesh_resp.write(protocol) < 0:
            sandesh_init.logger().error('Http Response: Failed to encode sandesh (%s)', sandesh_resp.__class__.__name__)
            return
        sandesh_resp_xml = transport.getvalue()
        if not SandeshHttp._http_response:
            SandeshHttp._state = 'HXMLNew'
            SandeshHttp._http_response = cStringIO.StringIO()
            SandeshHttp._http_response.write(universal_xsl_str)
            if sandesh_resp._more:
                sandesh_name_end = sandesh_resp_xml.find(' ')
                if sandesh_name_end == -1:
                    sandesh_init.logger().error('Http Response: Failed to get Sandesh name (%s)', sandesh_resp.__class__.__name__)
                    return
                SandeshHttp._http_response_context = sandesh_resp_xml[1:sandesh_name_end]
                SandeshHttp._http_response.write('<__%s_list type="slist">' % (SandeshHttp._http_response_context))
                SandeshHttp._state = 'HXMLIncomplete'
        SandeshHttp._http_response.write(sandesh_resp_xml)
        if not sandesh_resp._more and SandeshHttp._state != 'HXMLNew':
            SandeshHttp._http_response.write('</__%s_list>' % (SandeshHttp._http_response_context))
    #end create_http_response

    @staticmethod
    def get_http_response():
        if SandeshHttp._http_response:
            bottle.response.headers['Content-Type'] = 'text/xsl'
            resp = SandeshHttp._http_response.getvalue()
            SandeshHttp._http_response.close()
            SandeshHttp._http_response = None
            SandeshHttp._http_response_context = None
            return resp
        return None
    #end get_http_response

    def _get_homepage(self):
        bottle.response.headers['Content-Type'] = 'text/html'
        return self._homepage
    #end _get_homepage

    def _get_indexpage(self, link):
        try:
            path = self._homepage_links[link]
        except KeyError:
            return self.http_error('Invalid Sandesh Request "%s"' % (link))
        else:
            return bottle.static_file(link, root=path)
    #end _get_indexpage

    def _get_webfiles(self):
        terms = bottle.request.url.rsplit('/', 1)
        fname = "/" + terms[1]
        upath = terms[0].split('//',1)[-1]
        pterms = upath.split('/',1)
        if len(pterms) == 1:
            fpath = self._webfiles_path + '/webs'
        else:
            fpath = self._webfiles_path + '/webs/' + pterms[1]
        #import pdb; pdb.set_trace()
        return bottle.static_file(fname, root=fpath)
    #end _get_webfiles

    def _create_homepage(self, pkg_list):
        self._homepage_links = {}
        for pkg_name in pkg_list:
            self._extract_http_requests(pkg_name)
        homepage_str = cStringIO.StringIO()

        homepage_str.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" +
            " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" +
            "" +
            "" +
            "<link href=\"css/style.css\" rel=\"stylesheet\" type=\"text/css\"/>" +
            ("<title>%s</title>" % self._module))

        homepage_str.write('
Modules for %s
' % (self._module))
        for link in self._homepage_links.iterkeys():
            http_link = '%s
' % (link, link[:link.find('.')])
            homepage_str.write(http_link)
        self._homepage = homepage_str.getvalue()
        homepage_str.close()
    #end _create_homepage

    def _extract_http_requests(self, package):
        try:
            imp_pkg = __import__(package)
        except ImportError:
            self._logger.error('Failed to import package "%s"' % (package))
        else:
            try:
                pkg_path = imp_pkg.__path__
            except AttributeError:
                self._logger.error('Failed to get package [%s] path' % (package))
                return
            for importer, mod, ispkg in \
                pkgutil.walk_packages(path=pkg_path, prefix=imp_pkg.__name__+'.'):
                if ispkg:
                    sub_pkg = mod
                else:
                    if 'http_request' == mod.rsplit('.', 1)[-1]:
                        self._add_http_request_links(pkg_path[0], sub_pkg, mod)
    #end _extract_http_requests

    def _add_http_request_links(self, pkg_path, sub_pkg, mod):
        try:
            http_module = importlib.import_module(mod)
        except ImportError:
            self._logger.error('Failed to import Module "%s"' % (mod))
        else:
            try:
                http_req_list = getattr(http_module, '_HTTP_REQUEST_LIST')
            except AttributeError:
                self._logger.error('"%s" module does not have http request list' % (mod))
            else:
                # Add the link to the homepage, only if the request list is non-empty
                if len(http_req_list):
                    link = sub_pkg.rsplit('.', 1)[-1]+'.xml'
                    sub_path = sub_pkg.split('.', 1)[-1].replace('.', '/')
                    path = pkg_path + '/' + sub_path
                    self._logger.debug('Add [%s:%s] to home page' % (link, path))
                    # TODO: Check for the existence of the html file
                    self._homepage_links[link] = path
                    self._register_http_requests(http_req_list)
    #end _add_http_request_links

    def _register_http_requests(self, http_req_list):
        for req in http_req_list:
            self._logger.debug('Add http request [%s]' % (req['uri']))
            self._http_request_dict[req['uri']] = req['method']
            self._http_app.route(req['uri'], 'GET', self._http_handle_request)
    #end _register_http_requests

    def _http_handle_request(self):
        # Call the handler
        method = self._http_request_dict[bottle.request.path]
        return method(self._sandesh)
    #end _http_handle_request

#end class SandeshHttp
<commit_msg>contrail-snmp-collector restart failing<commit_after>#
# Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
#

#
# Sandesh Http
#

import pkgutil
import importlib
import sys
#
# Prevent:
# Exception KeyError: KeyError(40918224,) in <module 'threading' from '/usr/lib64/python2.7/threading.pyc'> ignored
# as per
# http://stackoverflow.com/questions/8774958/keyerror-in-module-threading-after-a-successful-py-test-run
#
if 'threading' in sys.modules:
    del sys.modules['threading']
from gevent import monkey; monkey.patch_all()
import wsgiref
from wsgiref.simple_server import make_server
import bottle
import cStringIO
from transport import TTransport
from protocol import TXMLProtocol
import os
import socket

class SandeshHttp(object):

    _HTTP_SERVER_IP = '0.0.0.0'
    _http_response = None
    _http_response_context = None
    _logger = None

    WebFilesList = [
    '/css/bootstrap.min.css',
    '/css/DT_bootstrap.css',
    '/css/images/sort_asc.png',
    '/css/images/sort_asc_disabled.png',
    '/css/images/sort_both.png',
    '/css/images/sort_desc.png',
    '/css/images/sort_desc_disabled.png',
    '/css/style.css',
    '/js/bootstrap.min.js',
    '/js/DT_bootstrap.js',
    '/js/jquery-2.0.3.min.js',
    '/js/jquery.dataTables.min.js',
    '/js/util.js',
    '/universal_parse.xsl']

    def __init__(self, sandesh, module, port, pkg_list):
        self._sandesh = sandesh
        self._logger = sandesh.logger()
        self._module = module
        self._http_port = port
        self._http_request_dict = {}
        self._http_app = bottle.Bottle()
        self._create_homepage(pkg_list)
        # Register the homepage
        self._http_app.route('/', 'GET', self._get_homepage)
        self._http_app.route('/index.html', 'GET', self._get_homepage)
        self._http_app.route('/<link:re:\w+.xml>', 'GET', self._get_indexpage)
        # Get the path of universal_parse.xsl and jquery and register the same
        self._webfiles_path = None
        self._universal_parse_xsl_path = None
        self._jquery_collapse_storage_js_path = None
        self._jquery_collapse_js_path = None
        self._jquery_1_8_1_js_path = None
        try:
            imp_pysandesh = __import__('pysandesh')
        except ImportError:
            self._logger.error('Failed to import "pysandesh"')
        else:
            self._webfiles_path = imp_pysandesh.__path__[0]
            self._universal_parse_xsl_path = imp_pysandesh.__path__[0]
            self._jquery_collapse_storage_js_path = imp_pysandesh.__path__[0]
            self._jquery_collapse_js_path = imp_pysandesh.__path__[0]
            self._jquery_1_8_1_js_path = imp_pysandesh.__path__[0]

        for elem in SandeshHttp.WebFilesList:
            #import pdb; pdb.set_trace()
            self._http_app.route(elem, 'GET', self._get_webfiles)

    #end __init__

    def start_http_server(self):
        try:
            svr = make_server(SandeshHttp._HTTP_SERVER_IP, self._http_port,
                              self._http_app)
        except socket.error as e:
            self._logger.error('Unable to open HTTP Port %d, %s' % (self._http_port, e))
            sys.exit()
        self._http_port = svr.server_port
        self._logger.error('Starting Introspect on HTTP Port %d' % self._http_port)
        self._sandesh.record_port("http", self._http_port)
        svr.allow_reuse_address = True
        svr.serve_forever()

    #end start_http_server

    def get_port(self):
        return self._http_port
    #end get_port

    @staticmethod
    def http_error(err_msg):
        return '
%s
' % (err_msg)
    #end http_error

    @staticmethod
    def create_http_response(sandesh_resp, sandesh_init):
        universal_xsl_str = '<?xml-stylesheet type="text/xsl" href="/universal_parse.xsl"?>'
        transport = TTransport.TMemoryBuffer()
        protocol_factory = TXMLProtocol.TXMLProtocolFactory()
        protocol = protocol_factory.getProtocol(transport)
        if sandesh_resp.write(protocol) < 0:
            sandesh_init.logger().error('Http Response: Failed to encode sandesh (%s)', sandesh_resp.__class__.__name__)
            return
        sandesh_resp_xml = transport.getvalue()
        if not SandeshHttp._http_response:
            SandeshHttp._state = 'HXMLNew'
            SandeshHttp._http_response = cStringIO.StringIO()
            SandeshHttp._http_response.write(universal_xsl_str)
            if sandesh_resp._more:
                sandesh_name_end = sandesh_resp_xml.find(' ')
                if sandesh_name_end == -1:
                    sandesh_init.logger().error('Http Response: Failed to get Sandesh name (%s)', sandesh_resp.__class__.__name__)
                    return
                SandeshHttp._http_response_context = sandesh_resp_xml[1:sandesh_name_end]
                SandeshHttp._http_response.write('<__%s_list type="slist">' % (SandeshHttp._http_response_context))
                SandeshHttp._state = 'HXMLIncomplete'
        SandeshHttp._http_response.write(sandesh_resp_xml)
        if not sandesh_resp._more and SandeshHttp._state != 'HXMLNew':
            SandeshHttp._http_response.write('</__%s_list>' % (SandeshHttp._http_response_context))
    #end create_http_response

    @staticmethod
    def get_http_response():
        if SandeshHttp._http_response:
            bottle.response.headers['Content-Type'] = 'text/xsl'
            resp = SandeshHttp._http_response.getvalue()
            SandeshHttp._http_response.close()
            SandeshHttp._http_response = None
            SandeshHttp._http_response_context = None
            return resp
        return None
    #end get_http_response

    def _get_homepage(self):
        bottle.response.headers['Content-Type'] = 'text/html'
        return self._homepage
    #end _get_homepage

    def _get_indexpage(self, link):
        try:
            path = self._homepage_links[link]
        except KeyError:
            return self.http_error('Invalid Sandesh Request "%s"' % (link))
        else:
            return bottle.static_file(link, root=path)
    #end _get_indexpage

    def _get_webfiles(self):
        terms = bottle.request.url.rsplit('/', 1)
        fname = "/" + terms[1]
        upath = terms[0].split('//',1)[-1]
        pterms = upath.split('/',1)
        if len(pterms) == 1:
            fpath = self._webfiles_path + '/webs'
        else:
            fpath = self._webfiles_path + '/webs/' + pterms[1]
        #import pdb; pdb.set_trace()
        return bottle.static_file(fname, root=fpath)
    #end _get_webfiles

    def _create_homepage(self, pkg_list):
        self._homepage_links = {}
        for pkg_name in pkg_list:
            self._extract_http_requests(pkg_name)
        homepage_str = cStringIO.StringIO()

        homepage_str.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" +
            " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" +
            "" +
            "" +
            "<link href=\"css/style.css\" rel=\"stylesheet\" type=\"text/css\"/>" +
            ("<title>%s</title>" % self._module))

        homepage_str.write('
Modules for %s
' % (self._module))
        for link in self._homepage_links.iterkeys():
            http_link = '%s
' % (link, link[:link.find('.')])
            homepage_str.write(http_link)
        self._homepage = homepage_str.getvalue()
        homepage_str.close()
    #end _create_homepage

    def _extract_http_requests(self, package):
        try:
            imp_pkg = __import__(package)
        except ImportError:
            self._logger.error('Failed to import package "%s"' % (package))
        else:
            try:
                pkg_path = imp_pkg.__path__
            except AttributeError:
                self._logger.error('Failed to get package [%s] path' % (package))
                return
            for importer, mod, ispkg in \
                pkgutil.walk_packages(path=pkg_path, prefix=imp_pkg.__name__+'.'):
                if ispkg:
                    sub_pkg = mod
                else:
                    if 'http_request' == mod.rsplit('.', 1)[-1]:
                        self._add_http_request_links(pkg_path[0], sub_pkg, mod)
    #end _extract_http_requests

    def _add_http_request_links(self, pkg_path, sub_pkg, mod):
        try:
            http_module = importlib.import_module(mod)
        except ImportError:
            self._logger.error('Failed to import Module "%s"' % (mod))
        else:
            try:
                http_req_list = getattr(http_module, '_HTTP_REQUEST_LIST')
            except AttributeError:
                self._logger.error('"%s" module does not have http request list' % (mod))
            else:
                # Add the link to the homepage, only if the request list is non-empty
                if len(http_req_list):
                    link = sub_pkg.rsplit('.', 1)[-1]+'.xml'
                    sub_path = sub_pkg.split('.', 1)[-1].replace('.', '/')
                    path = pkg_path + '/' + sub_path
                    self._logger.debug('Add [%s:%s] to home page' % (link, path))
                    # TODO: Check for the existence of the html file
                    self._homepage_links[link] = path
                    self._register_http_requests(http_req_list)
    #end _add_http_request_links

    def _register_http_requests(self, http_req_list):
        for req in http_req_list:
            self._logger.debug('Add http request [%s]' % (req['uri']))
            self._http_request_dict[req['uri']] = req['method']
            self._http_app.route(req['uri'], 'GET', self._http_handle_request)
    #end _register_http_requests

    def _http_handle_request(self):
        # Call the handler
        method = self._http_request_dict[bottle.request.path]
        return method(self._sandesh)
    #end _http_handle_request

#end class SandeshHttp
<|endoftext|>


<commit_before>"""
Make mistletoe easier to import.
"""

__version__ = "0.8.0"
__all__ = ['html_renderer', 'ast_renderer', 'block_token', 'block_tokenizer',
           'span_token', 'span_tokenizer']

from mistletoe.block_token import Document
from mistletoe.base_renderer import BaseRenderer
from mistletoe.html_renderer import HTMLRenderer

def markdown(iterable, renderer=HTMLRenderer):
    """
    Output HTML with default settings.
    Enables inline and block-level HTML tags.
    """
    with renderer() as renderer:
        return renderer.render(Document(iterable))
<commit_msg>chore: next dev version<commit_after>"""
Make mistletoe easier to import.
"""

__version__ = "0.8.1-SNAPSHOT"
__all__ = ['html_renderer', 'ast_renderer', 'block_token', 'block_tokenizer',
           'span_token', 'span_tokenizer']

from mistletoe.block_token import Document
from mistletoe.base_renderer import BaseRenderer
from mistletoe.html_renderer import HTMLRenderer

def markdown(iterable, renderer=HTMLRenderer):
    """
    Output HTML with default settings.
    Enables inline and block-level HTML tags.
    """
    with renderer() as renderer:
        return renderer.render(Document(iterable))
<|endoftext|>


<commit_before>from django.test import TestCase
from explorer.actions import generate_report_action
from explorer.tests.factories import SimpleQueryFactory
from explorer import app_settings
from explorer.utils import passes_blacklist, schema_info, param, swap_params, extract_params,\
    shared_dict_update, EXPLORER_PARAM_TOKEN, get_params_from_request, get_params_for_url
from mock import Mock

class TestSqlBlacklist(TestCase):

    def setUp(self):
        self.orig = app_settings.EXPLORER_SQL_BLACKLIST
        self.orig_wl = app_settings.EXPLORER_SQL_WHITELIST

    def tearDown(self):
        app_settings.EXPLORER_SQL_BLACKLIST = self.orig
        app_settings.EXPLORER_SQL_WHITELIST = self.orig_wl

    def test_overriding_blacklist(self):
        app_settings.EXPLORER_SQL_BLACKLIST = []
        r = SimpleQueryFactory(sql="SELECT 1+1 AS \"DELETE\";")
        fn = generate_report_action()
        result = fn(None, None, [r, ])
        self.assertEqual(result.content, b'DELETE\r\n2\r\n')

    def test_default_blacklist_prevents_deletes(self):
        r = SimpleQueryFactory(sql="SELECT 1+1 AS \"DELETE\";")
        fn = generate_report_action()
        result = fn(None, None, [r, ])
        self.assertEqual(result.content.decode('utf-8'), '0')

    def test_queries_deleting_stuff_are_not_ok(self):
        sql = "'distraction'; deLeTe from table; SELECT 1+1 AS TWO; drop view foo;"
        passes, words = passes_blacklist(sql)
        self.assertFalse(passes)
        self.assertTrue(len(words), 2)
        self.assertEqual(words[0], 'DROP')
        self.assertEqual(words[1], 'DELETE')

    def test_queries_dropping_views_is_not_ok_and_not_case_sensitive(self):
        sql = "SELECT 1+1 AS TWO; drop ViEw foo;"
        self.assertFalse(passes_blacklist(sql)[0])

    def test_sql_whitelist_ok(self):
        app_settings.EXPLORER_SQL_WHITELIST = ['dropper']
        sql = "SELECT 1+1 AS TWO; dropper ViEw foo;"
        self.assertTrue(passes_blacklist(sql)[0])

class TestSchemaInfo(TestCase):

    def test_schema_info_returns_valid_data(self):
        res = schema_info()
        tables = [a[1] for a in res]
        self.assertIn('explorer_query', tables)

    def test_app_exclusion_list(self):
        app_settings.EXPLORER_SCHEMA_EXCLUDE_APPS = ('explorer',)
        res = schema_info()
        app_settings.EXPLORER_SCHEMA_EXCLUDE_APPS = ('',)
        tables = [a[1] for a in res]
        self.assertNotIn('explorer_query', tables)

class TestParams(TestCase):

    def test_swappable_params_are_built_correctly(self):
        expected = EXPLORER_PARAM_TOKEN + 'foo' + EXPLORER_PARAM_TOKEN
        self.assertEqual(expected, param('foo'))

    def test_params_get_swapped(self):
        sql = 'please swap $$this$$ and $$THat$$'
        expected = 'please swap here and there'
        params = {'this': 'here', 'that': 'there'}
        got = swap_params(sql, params)
        self.assertEqual(got, expected)

    def test_empty_params_does_nothing(self):
        sql = 'please swap $$this$$ and $$that$$'
        params = None
        got = swap_params(sql, params)
        self.assertEqual(got, sql)

    def test_non_string_param_gets_swapper(self):
        sql = 'please swap $$this$$'
        expected = 'please swap 1'
        params = {'this': 1}
        got = swap_params(sql, params)
        self.assertEqual(got, expected)

    def _assertSwap(self, tuple):
        self.assertEqual(extract_params(tuple[0]), tuple[1])

    def test_extracting_params(self):
        tests = [
            ('please swap $$this0$$',                {'this0': ''}),
            ('please swap $$THis0$$',                {'this0': ''}),
            ('please swap $$this6$$ $$this6:that$$', {'this6': 'that'}),
            ('please swap $$this_7:foo, bar$$',      {'this_7': 'foo, bar'}),
            ('please swap $$this8:$$',               {}),
            ('do nothing with $$this1 $$',           {}),
            ('do nothing with $$this2 :$$',          {}),
            ('do something with $$this3: $$',        {'this3': ' '}),
            ('do nothing with $$this4: ',            {}),
            ('do nothing with $$this5$that$$',       {}),
        ]
        for s in tests:
            self._assertSwap(s)

    def test_shared_dict_update(self):
        source = {'foo': 1, 'bar': 2}
        target = {'bar': None}  # ha ha!
        self.assertEqual({'bar': 2}, shared_dict_update(target, source))

    def test_get_params_from_url(self):
        r = Mock()
        r.GET = {'params': 'foo:bar|qux:mux'}
        res = get_params_from_request(r)
        self.assertEqual(res['foo'], 'bar')
        self.assertEqual(res['qux'], 'mux')

    def test_get_params_for_request(self):
        q = SimpleQueryFactory(params={'a': 1, 'b': 2})
        self.assertEqual(get_params_for_url(q), 'a:1|b:2')

    def test_get_params_for_request_empty(self):
        q = SimpleQueryFactory()
        self.assertEqual(get_params_for_url(q), None)
<commit_msg>fixing nondeterministic test<commit_after>from django.test import TestCase
from explorer.actions import generate_report_action
from explorer.tests.factories import SimpleQueryFactory
from explorer import app_settings
from explorer.utils import passes_blacklist, schema_info, param, swap_params, extract_params,\
    shared_dict_update, EXPLORER_PARAM_TOKEN, get_params_from_request, get_params_for_url
from mock import Mock

class TestSqlBlacklist(TestCase):

    def setUp(self):
        self.orig = app_settings.EXPLORER_SQL_BLACKLIST
        self.orig_wl = app_settings.EXPLORER_SQL_WHITELIST

    def tearDown(self):
        app_settings.EXPLORER_SQL_BLACKLIST = self.orig
        app_settings.EXPLORER_SQL_WHITELIST = self.orig_wl

    def test_overriding_blacklist(self):
        app_settings.EXPLORER_SQL_BLACKLIST = []
        r = SimpleQueryFactory(sql="SELECT 1+1 AS \"DELETE\";")
        fn = generate_report_action()
        result = fn(None, None, [r, ])
        self.assertEqual(result.content, b'DELETE\r\n2\r\n')

    def test_default_blacklist_prevents_deletes(self):
        r = SimpleQueryFactory(sql="SELECT 1+1 AS \"DELETE\";")
        fn = generate_report_action()
        result = fn(None, None, [r, ])
        self.assertEqual(result.content.decode('utf-8'), '0')

    def test_queries_deleting_stuff_are_not_ok(self):
        sql = "'distraction'; deLeTe from table; SELECT 1+1 AS TWO; drop view foo;"
        passes, words = passes_blacklist(sql)
        self.assertFalse(passes)
        self.assertTrue(len(words), 2)
        self.assertEqual(words[0], 'DROP')
        self.assertEqual(words[1], 'DELETE')

    def test_queries_dropping_views_is_not_ok_and_not_case_sensitive(self):
        sql = "SELECT 1+1 AS TWO; drop ViEw foo;"
        self.assertFalse(passes_blacklist(sql)[0])

    def test_sql_whitelist_ok(self):
        app_settings.EXPLORER_SQL_WHITELIST = ['dropper']
        sql = "SELECT 1+1 AS TWO; dropper ViEw foo;"
        self.assertTrue(passes_blacklist(sql)[0])

class TestSchemaInfo(TestCase):

    def test_schema_info_returns_valid_data(self):
        res = schema_info()
        tables = [a[1] for a in res]
        self.assertIn('explorer_query', tables)

    def test_app_exclusion_list(self):
        app_settings.EXPLORER_SCHEMA_EXCLUDE_APPS = ('explorer',)
        res = schema_info()
        app_settings.EXPLORER_SCHEMA_EXCLUDE_APPS = ('',)
        tables = [a[1] for a in res]
        self.assertNotIn('explorer_query', tables)

class TestParams(TestCase):

    def test_swappable_params_are_built_correctly(self):
        expected = EXPLORER_PARAM_TOKEN + 'foo' + EXPLORER_PARAM_TOKEN
        self.assertEqual(expected, param('foo'))

    def test_params_get_swapped(self):
        sql = 'please swap $$this$$ and $$THat$$'
        expected = 'please swap here and there'
        params = {'this': 'here', 'that': 'there'}
        got = swap_params(sql, params)
        self.assertEqual(got, expected)

    def test_empty_params_does_nothing(self):
        sql = 'please swap $$this$$ and $$that$$'
        params = None
        got = swap_params(sql, params)
        self.assertEqual(got, sql)

    def test_non_string_param_gets_swapper(self):
        sql = 'please swap $$this$$'
        expected = 'please swap 1'
        params = {'this': 1}
        got = swap_params(sql, params)
        self.assertEqual(got, expected)

    def _assertSwap(self, tuple):
        self.assertEqual(extract_params(tuple[0]), tuple[1])

    def test_extracting_params(self):
        tests = [
            ('please swap $$this0$$',                {'this0': ''}),
            ('please swap $$THis0$$',                {'this0': ''}),
            ('please swap $$this6$$ $$this6:that$$', {'this6': 'that'}),
            ('please swap $$this_7:foo, bar$$',      {'this_7': 'foo, bar'}),
            ('please swap $$this8:$$',               {}),
            ('do nothing with $$this1 $$',           {}),
            ('do nothing with $$this2 :$$',          {}),
            ('do something with $$this3: $$',        {'this3': ' '}),
            ('do nothing with $$this4: ',            {}),
            ('do nothing with $$this5$that$$',       {}),
        ]
        for s in tests:
            self._assertSwap(s)

    def test_shared_dict_update(self):
        source = {'foo': 1, 'bar': 2}
        target = {'bar': None}  # ha ha!
        self.assertEqual({'bar': 2}, shared_dict_update(target, source))

    def test_get_params_from_url(self):
        r = Mock()
        r.GET = {'params': 'foo:bar|qux:mux'}
        res = get_params_from_request(r)
        self.assertEqual(res['foo'], 'bar')
        self.assertEqual(res['qux'], 'mux')

    def test_get_params_for_request(self):
        q = SimpleQueryFactory(params={'a': 1, 'b': 2})
        # For some reason the order of the params is non-deterministic, causing the following to periodically fail:
        #     self.assertEqual(get_params_for_url(q), 'a:1|b:2')
        # So instead we go for the following, convoluted, asserts:
        res = get_params_for_url(q)
        res = res.split('|')
        expected = ['a:1', 'b:2']
        for e in expected:
            self.assertIn(e, res)

    def test_get_params_for_request_empty(self):
        q = SimpleQueryFactory()
        self.assertEqual(get_params_for_url(q), None)
<|endoftext|>


<commit_before>import numpy as np
import numpy.testing as npt
from scipy.linalg import hadamard
from sklearn.utils.fht import fht
from sklearn.utils.cyfht import fht as cyfht

def single(fht_type):
    input_ = np.array([1, 0, 1, 0, 0, 1, 1, 0], dtype=np.float64)
    copy = input_.copy()
    H = hadamard(8)
    fht_type(input_)
    npt.assert_array_equal(np.dot(copy, H), input_)

def test_all():
    single(fht)
    single(cyfht)
<commit_msg>test to check that fht/cyfht aborts on non-power-two input<commit_after>import numpy as np
import numpy.testing as npt
import nose.tools as nt
from scipy.linalg import hadamard
from sklearn.utils.fht import fht
from sklearn.utils.cyfht import fht as cyfht

def single(fht_type):
    input_ = np.array([1, 0, 1, 0, 0, 1, 1, 0], dtype=np.float64)
    copy = input_.copy()
    H = hadamard(8)
    fht_type(input_)
    npt.assert_array_equal(np.dot(copy, H), input_)

def test_exception_when_input_not_power_two():
    for fht_type in  [fht, cyfht]:
        yield nt.assert_raises, ValueError, fht_type, np.zeros(9, dtype=np.float64)

def test_all():
    single(fht)
    single(cyfht)
<|endoftext|>


<commit_before>import datetime
import fileinput
import gzip
import os
import re

from lxml import etree

import tripleoci.config as config
from tripleoci.config import log
from tripleoci.patches import Job
from tripleoci.utils import Web

# Jobs regexps
branch_re = re.compile(r"\+ export ZUUL_BRANCH=(\S+)")
ts_re = re.compile(r"(201\d-[01]\d-[0123]\d [012]\d:\d\d):\d\d\.\d\d\d")

class Periodic(object):
    """Periodic job object

        Class that actually parses periodic jobs HTML page.
        It tries to extract all available info from the page, but
        some info could be found only in console.html, for example
        job status. So it needs to download console.html for every job and
        to parse it also.
    """
    def __init__(self, url, down_path=config.DOWNLOAD_PATH, limit=None):
        self.per_url = url
        self.down_path = down_path
        self.limit = limit
        self.jobs = self.get_jobs()

    def _get_index(self):
        web = Web(self.per_url)
        req = web.get()
        if req is None or int(req.status_code) != 200:
            log.warning(
                "Trying again to download periodic page ".format(self.per_url))
            req = web.get()
            if req is None or int(req.status_code) != 200:
                log.error(
                    "Can not retrieve periodic page {}".format(self.per_url))
                return None
        return req.content

    def _get_console(self, job):
        path = os.path.join(
            self.down_path, job["log_hash"], "console.html.gz")
        if os.path.exists(path):
            log.debug("Console is already here: {}".format(path))
            return path
        web = Web(job["log_url"] + "/console.html.gz")
        req = web.get(ignore404=True)
        if req is not None and int(req.status_code) == 404:
            url = job["log_url"] + "/console.html"
            web = Web(url=url)
            log.debug("Trying to download raw console")
            req = web.get()
        if req is None or int(req.status_code) != 200:
            log.error("Failed to retrieve console: {}".format(job["log_url"]))
            return None
        else:
            if not os.path.exists(os.path.dirname(path)):
                os.makedirs(os.path.dirname(path))
            with gzip.open(path, "wb") as f:
                f.write(req.content)
        return path

    def parse_index(self, text):
        jobs = []
        et = etree.HTML(text)
        trs = [i for i in et.xpath("//tr") if not i.xpath("th")][1:]
        for tr in trs:
            job = {}
            td1, td2 = tr.xpath("td")[1:3]
            lhash = td1.xpath("a")[0].attrib['href'].rstrip("/")
            job["log_hash"] = lhash
            job["log_url"] = self.per_url.rstrip("/") + "/" + lhash
            job["ts"] = datetime.datetime.strptime(td2.text.strip(),
                                                   "%Y-%m-%d %H:%M")
            job["name"] = self.per_url.rstrip("/").split("/")[-1]
            jobs.append(job)
        return sorted(jobs, key=lambda x: x['ts'], reverse=True)

    def _parse_ts(self, ts):
        return datetime.datetime.strptime(ts, "%Y-%m-%d %H:%M")

    def _get_more_data(self, j):
        def delta(e, s):
            return (self._parse_ts(e) - self._parse_ts(s)).seconds / 60

        start = end = last = None
        j.update({
            'status': 'FAILURE',
            'fail': True,
            'branch': '',
            'length': 0,
        })
        console = self._get_console(j)
        if not console:
            log.error("Failed to get console for periodic {}".format(repr(j)))
            return None
        else:
            finput = fileinput.FileInput(console,
                                         openhook=fileinput.hook_compressed)
            for line in finput:
                line = line.decode()
                if ("Finished: SUCCESS" in line or
                        '[Zuul] Job complete, result: SUCCESS' in line):
                    j['fail'] = False
                    j['status'] = 'SUCCESS'
                elif ("Finished: FAILURE" in line or
                        '[Zuul] Job complete, result: FAILURE' in line):
                    j['fail'] = True
                    j['status'] = 'FAILURE'
                elif ("Finished: ABORTED" in line or
                        '[Zuul] Job complete, result: ABORTED' in line):
                    j['fail'] = True
                    j['status'] = 'ABORTED'
                if branch_re.search(line):
                    j['branch'] = branch_re.search(line).group(1)
                if 'Started by user' in line or '[Zuul] Launched by' in line:
                    start = ts_re.search(line).group(1)
                if "Finished: " in line or '[Zuul] Job complete' in line:
                    end = ts_re.search(line).group(1)
                if ts_re.search(line):
                    last = ts_re.search(line).group(1)
            end = end or last
            j['length'] = delta(end, start) if start and end else 0
            j['ts'] = self._parse_ts(end) if end else j['ts']
            finput.close()
        return j

    def get_jobs(self):
        index = self._get_index()
        if index:
            jobs = self.parse_index(index)[:self.limit]
        else:
            jobs = []
        for j in jobs:
            raw = self._get_more_data(j)
            if raw is None:
                log.error("Failed to process job {}".format(repr(j)))
            else:
                yield PeriodicJob(**raw)

class PeriodicJob(Job):
    """Class that contains all necessary info for periodic job."""
    def __init__(self, **kwargs):
        super(PeriodicJob, self).__init__(
            name=kwargs["name"],
            log_url=kwargs["log_url"],
            status=kwargs["status"],
            length=kwargs["length"],
            timestamp=kwargs["ts"],
            patch=None,
            patchset=None
        )
        self.periodic = True
<commit_msg>Avoid parsing errors<commit_after>import datetime
import fileinput
import gzip
import os
import re

from lxml import etree

import tripleoci.config as config
from tripleoci.config import log
from tripleoci.patches import Job
from tripleoci.utils import Web

# Jobs regexps
branch_re = re.compile(r"\+ export ZUUL_BRANCH=(\S+)")
ts_re = re.compile(r"(201\d-[01]\d-[0123]\d [012]\d:\d\d):\d\d\.\d\d\d")

class Periodic(object):
    """Periodic job object

        Class that actually parses periodic jobs HTML page.
        It tries to extract all available info from the page, but
        some info could be found only in console.html, for example
        job status. So it needs to download console.html for every job and
        to parse it also.
    """
    def __init__(self, url, down_path=config.DOWNLOAD_PATH, limit=None):
        self.per_url = url
        self.down_path = down_path
        self.limit = limit
        self.jobs = self.get_jobs()

    def _get_index(self):
        web = Web(self.per_url)
        req = web.get()
        if req is None or int(req.status_code) != 200:
            log.warning(
                "Trying again to download periodic page ".format(self.per_url))
            req = web.get()
            if req is None or int(req.status_code) != 200:
                log.error(
                    "Can not retrieve periodic page {}".format(self.per_url))
                return None
        return req.content

    def _get_console(self, job):
        path = os.path.join(
            self.down_path, job["log_hash"], "console.html.gz")
        if os.path.exists(path):
            log.debug("Console is already here: {}".format(path))
            return path
        web = Web(job["log_url"] + "/console.html.gz")
        req = web.get(ignore404=True)
        if req is not None and int(req.status_code) == 404:
            url = job["log_url"] + "/console.html"
            web = Web(url=url)
            log.debug("Trying to download raw console")
            req = web.get()
        if req is None or int(req.status_code) != 200:
            log.error("Failed to retrieve console: {}".format(job["log_url"]))
            return None
        else:
            if not os.path.exists(os.path.dirname(path)):
                os.makedirs(os.path.dirname(path))
            with gzip.open(path, "wb") as f:
                f.write(req.content)
        return path

    def parse_index(self, text):
        jobs = []
        et = etree.HTML(text)
        trs = [i for i in et.xpath("//tr") if not i.xpath("th")][1:]
        for tr in trs:
            job = {}
            td1, td2 = tr.xpath("td")[1:3]
            lhash = td1.xpath("a")[0].attrib['href'].rstrip("/")
            job["log_hash"] = lhash
            job["log_url"] = self.per_url.rstrip("/") + "/" + lhash
            job["ts"] = datetime.datetime.strptime(td2.text.strip(),
                                                   "%Y-%m-%d %H:%M")
            job["name"] = self.per_url.rstrip("/").split("/")[-1]
            jobs.append(job)
        return sorted(jobs, key=lambda x: x['ts'], reverse=True)

    def _parse_ts(self, ts):
        return datetime.datetime.strptime(ts, "%Y-%m-%d %H:%M")

    def _get_more_data(self, j):
        def delta(e, s):
            return (self._parse_ts(e) - self._parse_ts(s)).seconds / 60

        start = end = last = None
        j.update({
            'status': 'FAILURE',
            'fail': True,
            'branch': '',
            'length': 0,
        })
        console = self._get_console(j)
        if not console:
            log.error("Failed to get console for periodic {}".format(repr(j)))
            return None
        else:
            finput = fileinput.FileInput(console,
                                         openhook=fileinput.hook_compressed)
            for line in finput:
                line = line.decode()
                if ("Finished: SUCCESS" in line or
                        '[Zuul] Job complete, result: SUCCESS' in line):
                    j['fail'] = False
                    j['status'] = 'SUCCESS'
                elif ("Finished: FAILURE" in line or
                        '[Zuul] Job complete, result: FAILURE' in line):
                    j['fail'] = True
                    j['status'] = 'FAILURE'
                elif ("Finished: ABORTED" in line or
                        '[Zuul] Job complete, result: ABORTED' in line):
                    j['fail'] = True
                    j['status'] = 'ABORTED'
                if branch_re.search(line):
                    j['branch'] = branch_re.search(line).group(1)
                try:
                    if 'Started by user' in line or '[Zuul] Launched by' in line:
                        start = ts_re.search(line).group(1)
                    if "Finished: " in line or '[Zuul] Job complete' in line:
                        end = ts_re.search(line).group(1)
                except Exception as e:
                    log.error(e)
                    return None
                if ts_re.search(line):
                    last = ts_re.search(line).group(1)
            end = end or last
            j['length'] = delta(end, start) if start and end else 0
            j['ts'] = self._parse_ts(end) if end else j['ts']
            finput.close()
        return j

    def get_jobs(self):
        index = self._get_index()
        if index:
            jobs = self.parse_index(index)[:self.limit]
        else:
            jobs = []
        for j in jobs:
            raw = self._get_more_data(j)
            if raw is None:
                log.error("Failed to process job {}".format(repr(j)))
            else:
                yield PeriodicJob(**raw)

class PeriodicJob(Job):
    """Class that contains all necessary info for periodic job."""
    def __init__(self, **kwargs):
        super(PeriodicJob, self).__init__(
            name=kwargs["name"],
            log_url=kwargs["log_url"],
            status=kwargs["status"],
            length=kwargs["length"],
            timestamp=kwargs["ts"],
            patch=None,
            patchset=None
        )
        self.periodic = True
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
====================================================
NanoGen model (:mod:`sknano.nanogen_gui._ng_model`)
====================================================

.. currentmodule:: sknano.nanogen_gui._ng_model

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

from ..nanogen import NanotubeBundle

__all__ = ['NGModel']

class NGModel(NanotubeBundle):
    """:py:mod:`~sknano.nanogen_gui` MVC model class."""
    def __init__(self):

        self.observers = []
        super(NGModel, self).__init__(n=10, m=10, verbose=True)

    def init(self):
        self.notify_observers()

    def _compute_bundle_params(self):
        super(NGModel, self).compute_bundle_params()
        self.notify_observers()

    @property
    def n(self):
        """Chiral index :math:`n`"""
        return self.n

    @n.setter
    def n(self, value):
        self.n = value
        self._compute_bundle_params()

    @property
    def m(self):
        """Chiral index :math:`m`"""
        return self.m

    @m.setter
    def m(self, value):
        self.m = value
        self._compute_bundle_params()

    #@property
    #def bond(self):
    #    return self.bond

    #@bond.setter
    #def bond(self, value):
    #    self.bond = value
    #    self._compute_bundle_params()

    @property
    def Lz(self):
        return self.Lz

    @Lz.setter
    def Lz(self, value):
        self.Lz = value
        self._compute_bundle_params()

    @property
    def nz(self):
        return self.nz

    @nz.setter
    def nz(self, value):
        self.nz = value
        self._compute_bundle_params()

    def register_observer(self, observer):
        self.observers.append(observer)

    def remove_observer(self, observer):
        self.observers.remove(observer)

    def notify_observers(self):
        for observer in self.observers[:]:
            observer.update_app_view()
<commit_msg>replace setting attributes with setting variables of superclass<commit_after># -*- coding: utf-8 -*-
"""
====================================================
NanoGen model (:mod:`sknano.nanogen_gui._ng_model`)
====================================================

.. currentmodule:: sknano.nanogen_gui._ng_model

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

from ..nanogen import NanotubeBundle

__all__ = ['NGModel']

class NGModel(NanotubeBundle):
    """:py:mod:`~sknano.nanogen_gui` MVC model class."""
    def __init__(self):

        self.observers = []
        super(NGModel, self).__init__(n=10, m=10)

    def init(self):
        self.notify_observers()

    def _compute_bundle_params(self):
        super(NGModel, self).compute_bundle_params()
        self.notify_observers()

    @property
    def n(self):
        """Chiral index :math:`n`"""
        return self._n

    @n.setter
    def n(self, value):
        self._n = value
        self._compute_bundle_params()
        #self.notify_observers()

    @property
    def m(self):
        """Chiral index :math:`m`"""
        return self._m

    @m.setter
    def m(self, value):
        self._m = value
        self._compute_bundle_params()
        #self.notify_observers()

    #@property
    #def bond(self):
    #    return self._bond

    #@bond.setter
    #def bond(self, value):
    #    self._bond = value
    #    self._compute_bundle_params()

    @property
    def Lz(self):
        return self._Lz

    @Lz.setter
    def Lz(self, value):
        self._Lz = value
        self._compute_bundle_params()
        #self.notify_observers()

    @property
    def nz(self):
        return self._nz

    @nz.setter
    def nz(self, value):
        self._nz = value
        self._compute_bundle_params()
        #self.notify_observers()

    def register_observer(self, observer):
        self.observers.append(observer)

    def remove_observer(self, observer):
        self.observers.remove(observer)

    def notify_observers(self):
        for observer in self.observers[:]:
            observer.update_app_view()
<|endoftext|>


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

from tg import expose, request, redirect, config
from tg.i18n import ugettext as _, lazy_ugettext as l_
from repoze.what.predicates import has_permission
from skylines.lib.base import BaseController
from skylines import model, files
from skylines.lib.igc.parser import SimpleParser

class FlightController(BaseController):
    def __init__(self, flight):
        self.flight = flight

    @expose('skylines.templates.flights.view')
    def index(self):
        parser = SimpleParser()
        fixes = parser.parse(file(files.filename_to_path(self.flight.filename)))

        return dict(page='flights', content=fixes)

class FlightIdController(BaseController):
    @expose()
    def lookup(self, id, *remainder):
        controller = FlightController(model.DBSession.query(model.Flight).get(int(id)))
        return controller, remainder

class FlightsController(BaseController):
    @expose('skylines.templates.flights.list')
    def index(self):
        flights = model.DBSession.query(model.Flight)
        return dict(page='flights', flights=flights,
                    files_uri=config['skylines.files.uri'])

    @expose('skylines.templates.flights.list')
    def my(self):
        flights = model.DBSession.query(model.Flight)
        if request.identity is not None:
            flights = flights.filter(model.Flight.owner == request.identity['user'])
        return dict(page='flights', flights=flights,
                    files_uri=config['skylines.files.uri'])

    id = FlightIdController()
<commit_msg>controllers.flights: generate HTTP 404<commit_after># -*- coding: utf-8 -*-

from tg import expose, request, redirect, config
from tg.i18n import ugettext as _, lazy_ugettext as l_
from repoze.what.predicates import has_permission
from webob.exc import HTTPNotFound
from skylines.lib.base import BaseController
from skylines import model, files
from skylines.lib.igc.parser import SimpleParser

class FlightController(BaseController):
    def __init__(self, flight):
        self.flight = flight

    @expose('skylines.templates.flights.view')
    def index(self):
        parser = SimpleParser()
        fixes = parser.parse(file(files.filename_to_path(self.flight.filename)))

        return dict(page='flights', content=fixes)

class FlightIdController(BaseController):
    @expose()
    def lookup(self, id, *remainder):
        flight = model.DBSession.query(model.Flight).get(int(id))
        if flight is None:
            raise HTTPNotFound

        controller = FlightController(flight)
        return controller, remainder

class FlightsController(BaseController):
    @expose('skylines.templates.flights.list')
    def index(self):
        flights = model.DBSession.query(model.Flight)
        return dict(page='flights', flights=flights,
                    files_uri=config['skylines.files.uri'])

    @expose('skylines.templates.flights.list')
    def my(self):
        flights = model.DBSession.query(model.Flight)
        if request.identity is not None:
            flights = flights.filter(model.Flight.owner == request.identity['user'])
        return dict(page='flights', flights=flights,
                    files_uri=config['skylines.files.uri'])

    id = FlightIdController()
<|endoftext|>