<commit_before>import numpy

import cupy
from cupy import util

def correlate(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional correlate.

    The array is correlated with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray, dtype or None): The array in which to place the
            output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of correlate.

    .. seealso:: :func:`scipy.ndimage.correlate`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  False)

def convolve(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional convolution.

    The array is convolved with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray, dtype or None): The array in which to place the
            output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of convolution.

    .. seealso:: :func:`scipy.ndimage.convolve`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  True)

def _get_output(output, input, shape=None):
    if shape is None:
        shape = input.shape
    if isinstance(output, cupy.ndarray):
        if output.shape != tuple(shape):
            raise ValueError('output shape is not correct')
    else:
        dtype = output
        if dtype is None:
            dtype = input.dtype
        output = cupy.zeros(shape, dtype)
    return output

def _correlate_or_convolve(input, weights, output, mode, cval, origin,
                           convolution):
    if input.dtype in (numpy.complex64, numpy.complex128, numpy.complex256):
        raise TypeError('Complex type not supported.')
    if not hasattr(origin, '__getitem__'):
        origin = [origin, ] * input.ndim
    else:
        origin = list(origin)
    wshape = [ii for ii in weights.shape if ii > 0]
    if len(wshape) != input.ndim:
        raise RuntimeError('filter weights array has incorrect shape.')
    if convolution:
        weights = weights[tuple([slice(None, None, -1)] * weights.ndim)]
        for ii in range(len(origin)):
            origin[ii] = -origin[ii]
            if weights.shape[ii] % 2 == 0:
                origin[ii] -= 1
    for _origin, lenw in zip(origin, wshape):
        if (lenw // 2 + _origin < 0) or (lenw // 2 + _origin >= lenw):
            raise ValueError('invalid origin')
    if mode not in ('reflect', 'constant', 'nearest', 'mirror', 'wrap'):
        msg = 'boundary mode not supported (actual: {}).'.format(mode)
        raise RuntimeError(msg)

    output = _get_output(output, input)
    if weights.size == 0:
        return output
    input = cupy.ascontiguousarray(input)
    weights = cupy.ascontiguousarray(weights, cupy.float64)
    return _get_correlete_kernel(
        input.ndim, mode, cval, input.shape, tuple(wshape), tuple(origin))(
        input, weights, output)

def _generate_boundary_condition_ops(mode, ix, xsize):
    if mode == 'reflect':
        ops = '''
        if ({ix} < 0) {{
            {ix} = - 1 - {ix};
        }}
        {ix} %= {xsize} * 2;
        {ix} = min({ix}, 2 * {xsize} - 1 - {ix});'''.format(ix=ix, xsize=xsize)
    elif mode == 'mirror':
        ops = '''
        if ({ix} < 0) {{
            {ix} = - {ix};
        }}
        if ({xsize} == 1) {{
            {ix} = 0;
        }} else {{
            {ix} = 1 + ({ix} - 1) % (({xsize} - 1) * 2);
            {ix} = min({ix}, 2 * {xsize} - 2 - {ix});
        }}'''.format(ix=ix, xsize=xsize)
    elif mode == 'nearest':
        ops = '''
        {ix} = min(max({ix}, 0), {xsize} - 1);'''.format(ix=ix, xsize=xsize)
    elif mode == 'wrap':
        ops = '''
        if ({ix} < 0) {{
            {ix} += (1 - ({ix} / {xsize})) * {xsize};
        }}
        {ix} %= {xsize};'''.format(ix=ix, xsize=xsize)
    elif mode == 'constant':
        ops = '''
        if ({ix} >= {xsize}) {{
            {ix} = -1;
        }}'''.format(ix=ix, xsize=xsize)
    return ops

def _generate_correlete_kernel(ndim, mode, cval, xshape, wshape, origin):
    in_params = 'raw X x, raw W w'
    out_params = 'Y y'

    ops = []
    ops.append('const int sx_{} = 1;'.format(ndim-1))
    for j in range(ndim-1, 0, -1):
        ops.append('int sx_{jm} = sx_{j} * {xsize_j};'.
                   format(jm=j-1, j=j, xsize_j=xshape[j]))
    ops.append('int _i = i;')
    for j in range(ndim-1, -1, -1):
        ops.append('int cx_{j} = _i % {xsize} - ({wsize} / 2) - ({origin});'
                   .format(j=j, xsize=xshape[j], wsize=wshape[j],
                           origin=origin[j]))
        if (j > 0):
            ops.append('_i /= {xsize};'.format(xsize=xshape[j]))
    ops.append('W sum = (W)0;')
    ops.append('int iw = 0;')

    for j in range(ndim):
        ops.append('''
    for (int iw_{j} = 0; iw_{j} < {wsize}; iw_{j}++)
    {{
        int ix_{j} = cx_{j} + iw_{j};'''.format(j=j, wsize=wshape[j]))
        ixvar = 'ix_{}'.format(j)
        ops.append(_generate_boundary_condition_ops(mode, ixvar, xshape[j]))
        ops.append('        ix_{j} *= sx_{j};'.format(j=j))

    _cond = ' || '.join(['(ix_{0} < 0)'.format(j) for j in range(ndim)])
    _expr = ' + '.join(['ix_{0}'.format(j) for j in range(ndim)])
    ops.append('''
        if ({cond}) {{
            sum += (W){cval} * w[iw];
        }} else {{
            int ix = {expr};
            sum += (W)x[ix] * w[iw];
        }}
        iw += 1;'''.format(cond=_cond, expr=_expr, cval=cval))

    ops.append('} ' * ndim)
    ops.append('y = (Y)sum;')
    operation = '\n'.join(ops)

    name = 'cupy_ndimage_correlate_{}d_{}_x{}_w{}'.format(
        ndim, mode, '_'.join(['{}'.format(j) for j in xshape]),
        '_'.join(['{}'.format(j) for j in wshape]))
    return in_params, out_params, operation, name

@util.memoize()
def _get_correlete_kernel(ndim, mode, cval, xshape, wshape, origin):
    # weights is always casted to float64 in order to get an output compatible
    # with SciPy, thought float32 might be sufficient when input dtype is low
    # precision.
    in_params, out_params, operation, name = _generate_correlete_kernel(
        ndim, mode, cval, xshape, wshape, origin)
    return cupy.ElementwiseKernel(in_params, out_params, operation, name)
<commit_msg>skip computations for zero valued coefficients<commit_after>import numpy

import cupy
from cupy import util

def correlate(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional correlate.

    The array is correlated with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray, dtype or None): The array in which to place the
            output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of correlate.

    .. seealso:: :func:`scipy.ndimage.correlate`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  False)

def convolve(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional convolution.

    The array is convolved with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray, dtype or None): The array in which to place the
            output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of convolution.

    .. seealso:: :func:`scipy.ndimage.convolve`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  True)

def _get_output(output, input, shape=None):
    if shape is None:
        shape = input.shape
    if isinstance(output, cupy.ndarray):
        if output.shape != tuple(shape):
            raise ValueError('output shape is not correct')
    else:
        dtype = output
        if dtype is None:
            dtype = input.dtype
        output = cupy.zeros(shape, dtype)
    return output

def _correlate_or_convolve(input, weights, output, mode, cval, origin,
                           convolution):
    if input.dtype in (numpy.complex64, numpy.complex128, numpy.complex256):
        raise TypeError('Complex type not supported.')
    if not hasattr(origin, '__getitem__'):
        origin = [origin, ] * input.ndim
    else:
        origin = list(origin)
    wshape = [ii for ii in weights.shape if ii > 0]
    if len(wshape) != input.ndim:
        raise RuntimeError('filter weights array has incorrect shape.')
    if convolution:
        weights = weights[tuple([slice(None, None, -1)] * weights.ndim)]
        for ii in range(len(origin)):
            origin[ii] = -origin[ii]
            if weights.shape[ii] % 2 == 0:
                origin[ii] -= 1
    for _origin, lenw in zip(origin, wshape):
        if (lenw // 2 + _origin < 0) or (lenw // 2 + _origin >= lenw):
            raise ValueError('invalid origin')
    if mode not in ('reflect', 'constant', 'nearest', 'mirror', 'wrap'):
        msg = 'boundary mode not supported (actual: {}).'.format(mode)
        raise RuntimeError(msg)

    output = _get_output(output, input)
    if weights.size == 0:
        return output
    input = cupy.ascontiguousarray(input)
    weights = cupy.ascontiguousarray(weights, cupy.float64)
    return _get_correlete_kernel(
        input.ndim, mode, cval, input.shape, tuple(wshape), tuple(origin))(
        input, weights, output)

def _generate_boundary_condition_ops(mode, ix, xsize):
    if mode == 'reflect':
        ops = '''
        if ({ix} < 0) {{
            {ix} = - 1 - {ix};
        }}
        {ix} %= {xsize} * 2;
        {ix} = min({ix}, 2 * {xsize} - 1 - {ix});'''.format(ix=ix, xsize=xsize)
    elif mode == 'mirror':
        ops = '''
        if ({ix} < 0) {{
            {ix} = - {ix};
        }}
        if ({xsize} == 1) {{
            {ix} = 0;
        }} else {{
            {ix} = 1 + ({ix} - 1) % (({xsize} - 1) * 2);
            {ix} = min({ix}, 2 * {xsize} - 2 - {ix});
        }}'''.format(ix=ix, xsize=xsize)
    elif mode == 'nearest':
        ops = '''
        {ix} = min(max({ix}, 0), {xsize} - 1);'''.format(ix=ix, xsize=xsize)
    elif mode == 'wrap':
        ops = '''
        if ({ix} < 0) {{
            {ix} += (1 - ({ix} / {xsize})) * {xsize};
        }}
        {ix} %= {xsize};'''.format(ix=ix, xsize=xsize)
    elif mode == 'constant':
        ops = '''
        if ({ix} >= {xsize}) {{
            {ix} = -1;
        }}'''.format(ix=ix, xsize=xsize)
    return ops

def _generate_correlete_kernel(ndim, mode, cval, xshape, wshape, origin):
    in_params = 'raw X x, raw W w'
    out_params = 'Y y'

    ops = []
    ops.append('const int sx_{} = 1;'.format(ndim-1))
    for j in range(ndim-1, 0, -1):
        ops.append('int sx_{jm} = sx_{j} * {xsize_j};'.
                   format(jm=j-1, j=j, xsize_j=xshape[j]))
    ops.append('int _i = i;')
    for j in range(ndim-1, -1, -1):
        ops.append('int cx_{j} = _i % {xsize} - ({wsize} / 2) - ({origin});'
                   .format(j=j, xsize=xshape[j], wsize=wshape[j],
                           origin=origin[j]))
        if (j > 0):
            ops.append('_i /= {xsize};'.format(xsize=xshape[j]))
    ops.append('W sum = (W)0;')
    ops.append('int iw = 0;')

    for j in range(ndim):
        ops.append('''
    for (int iw_{j} = 0; iw_{j} < {wsize}; iw_{j}++)
    {{
        int ix_{j} = cx_{j} + iw_{j};'''.format(j=j, wsize=wshape[j]))
        ixvar = 'ix_{}'.format(j)
        ops.append(_generate_boundary_condition_ops(mode, ixvar, xshape[j]))
        ops.append('        ix_{j} *= sx_{j};'.format(j=j))

    ops.append('W wval = w[iw];')
    ops.append("""
    if (wval == 0) {{
        iw += 1;
        continue;
    }}""")
    _cond = ' || '.join(['(ix_{0} < 0)'.format(j) for j in range(ndim)])
    _expr = ' + '.join(['ix_{0}'.format(j) for j in range(ndim)])
    ops.append('''
        if ({cond}) {{
            sum += (W){cval} * wval;
        }} else {{
            int ix = {expr};
            sum += (W)x[ix] * wval;
        }}
        iw += 1;'''.format(cond=_cond, expr=_expr, cval=cval))

    ops.append('} ' * ndim)
    ops.append('y = (Y)sum;')
    operation = '\n'.join(ops)

    name = 'cupy_ndimage_correlate_{}d_{}_x{}_w{}'.format(
        ndim, mode, '_'.join(['{}'.format(j) for j in xshape]),
        '_'.join(['{}'.format(j) for j in wshape]))
    return in_params, out_params, operation, name

@util.memoize()
def _get_correlete_kernel(ndim, mode, cval, xshape, wshape, origin):
    # weights is always casted to float64 in order to get an output compatible
    # with SciPy, thought float32 might be sufficient when input dtype is low
    # precision.
    in_params, out_params, operation, name = _generate_correlete_kernel(
        ndim, mode, cval, xshape, wshape, origin)
    return cupy.ElementwiseKernel(in_params, out_params, operation, name)
<|endoftext|>


<commit_before>import numpy

import cupy

def correlate(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional correlate.

    The array is correlated with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray or None): The array in which to place the output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of correlate.

    .. seealso:: :func:`scipy.ndimage.correlate`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  False)

def convolve(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional convolution.

    The array is convolved with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray or None): The array in which to place the output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of convolution.

    .. seealso:: :func:`scipy.ndimage.convolve`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  True)

def _get_output(output, input, shape=None):
    if shape is None:
        shape = input.shape
    if isinstance(output, cupy.ndarray):
        if output.shape != tuple(shape):
            raise ValueError('output shape is not correct')
    else:
        dtype = output
        if dtype is None:
            dtype = input.dtype
        output = cupy.zeros(shape, dtype)
    return output

def _correlate_or_convolve(input, weights, output, mode, cval, origin,
                           convolution):
    if input.dtype in (numpy.complex64, numpy.complex128, numpy.complex256):
        raise TypeError('Complex type not supported.')
    if not hasattr(origin, '__getitem__'):
        origin = [origin, ] * input.ndim
    wshape = [ii for ii in weights.shape if ii > 0]
    if len(wshape) != input.ndim:
        raise RuntimeError('filter weights array has incorrect shape.')
    if convolution:
        weights = weights[tuple([slice(None, None, -1)] * weights.ndim)]
        for ii in range(len(origin)):
            origin[ii] = - origin[ii]
            if not weights.shape[ii] & 1:
                origin[ii] -= 1
    for _origin, lenw in zip(origin, wshape):
        if (lenw // 2 + _origin < 0) or (lenw // 2 + _origin > lenw):
            raise ValueError('invalid origin')
    if mode not in ('reflect', 'constant', 'nearest', 'mirror', 'wrap'):
        msg = 'boundary mode not supported (actual: {}).'.format(mode)
        raise RuntimeError(msg)

    output = _get_output(output, input)
    input = cupy.ascontiguousarray(input.astype(output.dtype))
    weights = cupy.ascontiguousarray(weights.astype(output.dtype))
    in_params, out_params, operation, name = _create_correlete_kernel(
        input.ndim, mode, cval, input.shape, wshape, origin)
    return cupy.ElementwiseKernel(in_params, out_params, operation, name)(
        input, weights, output)

def _create_correlete_kernel(ndim, mode, cval, xshape, wshape, origin):
    in_params = ('raw T x, raw T w')
    out_params = 'T y'

    ops = []
    ops.append('const int sx_{} = 1;'.format(ndim-1))
    for j in range(ndim-2, -1, -1):
        ops.append('int sx_{0} = sx_{1} * {2};'.format(j, j+1, xshape[j+1]))
    ops.append('int _i = i;')
    for j in range(ndim-1, -1, -1):
        ops.append('int cx_{0} = _i % {1} - ({2} / 2) - ({3});'
                   .format(j, xshape[j], wshape[j], origin[j]))
        ops.append('_i /= {0};'.format(xshape[j]))
    ops.append('T sum = (T)0;')
    ops.append('int iw = 0;')

    for j in range(ndim):
        ops.append('for (int iw_{0} = 0; iw_{0} < {1}; iw_{0}++)'
                   .format(j, wshape[j]))
        ops.append('{')
        ops.append('    int ix_{0} = cx_{0} + iw_{0};'.format(j))
        # boundary condition
        if mode == 'reflect':
            ops.append('    if (ix_{0} < 0)'.format(j))
            ops.append('        ix_{0} = - 1 - ix_{0};'.format(j))
            ops.append('    ix_{0} %= {1} * 2;'.format(j, xshape[j]))
            ops.append('    ix_{0} = min(ix_{0}, 2 * {1} - 1 - ix_{0});'
                       .format(j, xshape[j]))
        elif mode == 'mirror':
            ops.append('    if (ix_{0} < 0)'.format(j))
            ops.append('        ix_{0} = - ix_{0};'.format(j))
            ops.append('    if ({} == 1)'.format(xshape[j]))
            ops.append('        ix_{0} = 0;'.format(j))
            ops.append('    else')
            ops.append('    {')
            ops.append('        ix_{0} = 1 + (ix_{0} - 1) % (({1} - 1) * 2);'
                       .format(j, xshape[j]))
            ops.append('        ix_{0} = min(ix_{0}, 2 * {1} - 2 - ix_{0});'
                       .format(j, xshape[j]))
            ops.append('    }')
        elif mode == 'nearest':
            ops.append('    ix_{0} = min(max(ix_{0}, 0), {1} - 1);'
                       .format(j, xshape[j]))
        elif mode == 'wrap':
            ops.append('    if (ix_{0} < 0)'.format(j))
            ops.append('        ix_{0} += (1 - (ix_{0} / {1})) * {1};'
                       .format(j, xshape[j]))
            ops.append('    ix_{0} %= {1};'.format(j, xshape[j]))
        elif mode == 'constant':
            ops.append('    if (ix_{0} >= {1})'.format(j, xshape[j]))
            ops.append('        ix_{0} = -1;'.format(j))
        ops.append('')

    if mode == 'constant':
        _str = " || ".join(['ix_{0} < 0'.format(j) for j in range(ndim)])
        ops.append('    if (' + _str + ')')
        ops.append('    {')
        ops.append('        sum += (T){} * w[iw];'.format(cval))
        ops.append('        iw += 1;')
        ops.append('        continue;')
        ops.append('    }')

    _str = " + ".join(['ix_{0} * sx_{0}'.format(j) for j in range(ndim)])
    ops.append('    int ix = ' + _str + ';')
    ops.append('    sum += x[ix] * w[iw];')
    ops.append('    iw += 1;')

    for j in range(ndim):
        ops.append('}')
    ops.append('y = sum;')
    operation = "\n".join(ops)

    name = 'cupy_ndimage_correlate_{}_{}d_x{}_w{}'.format(
        mode, ndim, "_".join(['{}'.format(j) for j in xshape]),
        "_".join(['{}'.format(j) for j in wshape]))
    return in_params, out_params, operation, name
<commit_msg>Improve code readability<commit_after>import numpy

import cupy

def correlate(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional correlate.

    The array is correlated with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray or None): The array in which to place the output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of correlate.

    .. seealso:: :func:`scipy.ndimage.correlate`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  False)

def convolve(input, weights, output=None, mode='reflect', cval=0.0, origin=0):
    """Multi-dimensional convolution.

    The array is convolved with the given kernel.

    Args:
        input (cupy.ndarray): The input array.
        weights (cupy.ndarray): Array of weights, same number of dimensions as
            input
        output (cupy.ndarray or None): The array in which to place the output.
        mode (str): The array borders are handled according to the given mode
            (``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``,
            ``'wrap'``). Default is ``'reflect'``.
        cval (scalar): Value to fill past edges of input if mode is
            ``constant``. Default is ``0.0``.
        origin (scalar or tuple of scalar): The origin parameter controls the
            placement of the filter, relative to the center of the current
            element of the input. Default of 0 is equivalent to
            ``(0,)*input.ndim``.

    Returns:
        cupy.ndarray: The result of convolution.

    .. seealso:: :func:`scipy.ndimage.convolve`
    """
    return _correlate_or_convolve(input, weights, output, mode, cval, origin,
                                  True)

def _get_output(output, input, shape=None):
    if shape is None:
        shape = input.shape
    if isinstance(output, cupy.ndarray):
        if output.shape != tuple(shape):
            raise ValueError('output shape is not correct')
    else:
        dtype = output
        if dtype is None:
            dtype = input.dtype
        output = cupy.zeros(shape, dtype)
    return output

def _correlate_or_convolve(input, weights, output, mode, cval, origin,
                           convolution):
    if input.dtype in (numpy.complex64, numpy.complex128, numpy.complex256):
        raise TypeError('Complex type not supported.')
    if not hasattr(origin, '__getitem__'):
        origin = [origin, ] * input.ndim
    wshape = [ii for ii in weights.shape if ii > 0]
    if len(wshape) != input.ndim:
        raise RuntimeError('filter weights array has incorrect shape.')
    if convolution:
        weights = weights[tuple([slice(None, None, -1)] * weights.ndim)]
        for ii in range(len(origin)):
            origin[ii] = - origin[ii]
            if not weights.shape[ii] & 1:
                origin[ii] -= 1
    for _origin, lenw in zip(origin, wshape):
        if (lenw // 2 + _origin < 0) or (lenw // 2 + _origin > lenw):
            raise ValueError('invalid origin')
    if mode not in ('reflect', 'constant', 'nearest', 'mirror', 'wrap'):
        msg = 'boundary mode not supported (actual: {}).'.format(mode)
        raise RuntimeError(msg)

    output = _get_output(output, input)
    input = cupy.ascontiguousarray(input.astype(output.dtype))
    weights = cupy.ascontiguousarray(weights.astype(output.dtype))
    in_params, out_params, operation, name = _generate_correlete_kernel(
        input.ndim, mode, cval, input.shape, wshape, origin)
    return cupy.ElementwiseKernel(in_params, out_params, operation, name)(
        input, weights, output)

def _generate_boundary_condition_ops(mode, ix, xsize):
    if mode == 'reflect':
        ops = '''
        if ({ix} < 0) {{
            {ix} = - 1 - {ix};
        }}
        {ix} %= {xsize} * 2;
        {ix} = min({ix}, 2 * {xsize} - 1 - {ix});'''.format(ix=ix, xsize=xsize)
    elif mode == 'mirror':
        ops = '''
        if ({ix} < 0) {{
            {ix} = - {ix};
        }}
        if ({xsize} == 1) {{
            {ix} = 0;
        }} else {{
            {ix} = 1 + ({ix} - 1) % (({xsize} - 1) * 2);
            {ix} = min({ix}, 2 * {xsize} - 2 - {ix});
        }}'''.format(ix=ix, xsize=xsize)
    elif mode == 'nearest':
        ops = '''
        {ix} = min(max({ix}, 0), {xsize} - 1);'''.format(ix=ix, xsize=xsize)
    elif mode == 'wrap':
        ops = '''
        if ({ix} < 0) {{
            {ix} += (1 - ({ix} / {xsize})) * {xsize};
        }}
        {ix} %= {xsize};'''.format(ix=ix, xsize=xsize)
    elif mode == 'constant':
        ops = '''
        if ({ix} >= {xsize}) {{
            {ix} = -1;
        }}'''.format(ix=ix, xsize=xsize)
    return ops

def _generate_correlete_kernel(ndim, mode, cval, xshape, wshape, origin):
    in_params = 'raw T x, raw T w'
    out_params = 'T y'

    ops = []
    ops.append('const int sx_{} = 1;'.format(ndim-1))
    for j in range(ndim-1, 0, -1):
        ops.append('int sx_{jm} = sx_{j} * {xsize_j};'.
                   format(jm=j-1, j=j, xsize_j=xshape[j]))
    ops.append('int _i = i;')
    for j in range(ndim-1, -1, -1):
        ops.append('int cx_{j} = _i % {xsize} - ({wsize} / 2) - ({origin});'
                   .format(j=j, xsize=xshape[j], wsize=wshape[j],
                           origin=origin[j]))
        if (j > 0):
            ops.append('_i /= {xsize};'.format(xsize=xshape[j]))
    ops.append('T sum = (T)0;')
    ops.append('int iw = 0;')

    for j in range(ndim):
        ops.append('''
    for (int iw_{j} = 0; iw_{j} < {wsize}; iw_{j}++)
    {{
        int ix_{j} = cx_{j} + iw_{j};'''.format(j=j, wsize=wshape[j]))
        ixvar = 'ix_{}'.format(j)
        ops.append(_generate_boundary_condition_ops(mode, ixvar, xshape[j]))

    _cond = " || ".join(['(ix_{0} < 0)'.format(j) for j in range(ndim)])
    _expr = " + ".join(['ix_{0} * sx_{0}'.format(j) for j in range(ndim)])
    ops.append('''
        if ({cond}) {{
            sum += (T){cval} * w[iw];
        }} else {{
            int ix = {expr};
            sum += x[ix] * w[iw];
        }}
        iw += 1;'''.format(cond=_cond, expr=_expr, cval=cval))

    ops.append('} ' * ndim)
    ops.append('y = sum;')
    operation = "\n".join(ops)

    name = 'cupy_ndimage_correlate_{}_{}d_x{}_w{}'.format(
        mode, ndim, "_".join(['{}'.format(j) for j in xshape]),
        "_".join(['{}'.format(j) for j in wshape]))
    return in_params, out_params, operation, name
<|endoftext|>


<commit_before>"""
    Python library for interacting with version 3 of the Capitol Words API

    Based heavily on the Sunlight Labs python-datacatalog wrapper:
    http://github.com/sunlightlabs/python-datacatalog/
"""

__author__ = "Joshua Ruihley <jruihley@sunlightfoundation.com>"
__version__ = "0.1"
__copyright__ = "Copyright (c) 2010 Sunlight Foundation"
__license__ = "BSD"

import urllib, httplib2
try:
    import json
except ImportError:
    import simplejson as json

class ApiError(Exception):
    """ Exception for API errors """

class capitolwords(object):

    def __init__(self, api_key=None, domain='capitolwords.org/api'):
        self.api_key = api_key
        self.domain = domain
        self.last_call = {}

    def store_last_call(self, url, params, response):
        self.last_call['url'] = url
        self.last_call['params'] = params
        self.last_call['response'] = response

    def _apicall(self, func, params=None, method='GET'):
        param_str = ''
        if params:
            params = dict([(k,v) for (k,v) in params.iteritems() if v is not None])
            param_str = '?%s' % urllib.urlencode(params)
        url = 'http://%s/%s.json%s' % (self.domain, func, param_str)
        print url

        try:
            h = httplib2.Http()
            response, content = h.request(url, method=method, headers=None, body=None)
            obj = json.loads(content)
            self.store_last_call(url, params, response)

            if 'errors' in obj:
                raise ApiError(obj['errors'], url, method, param_str)
            else:
                return obj
        except httplib2.HttpLib2Error, e:
            raise ApiError(e.read())
        except ValueError, e:
            raise ApiError('Invalid Response')

    def phrase_by_date_range(self, **params):
        result = capitolwords._apicall(self, 'dates', params)['results']
        return result

    def timeline(self, **params):
        result = capitolwords._apicall(self, 'chart/timeline', params)['results']
        return result

    def piechart(self, **params):
        result = capitolwords._apicall(self, 'chart/pie', params)['results']
        return result

    def phrase_by_entity_type(self, entity_type, **params):
        result = capitolwords._apicall(self, 'phrases/%s' % entity_type, params)['results']
        return result

    def top_phrases(self, **params):
        result = capitolwords._apicall(self, 'phrases', params)
        return result

    def get_legislator(self, **params):
        result = capitolwords._apicall(self, 'legislators', params)
        return result

    def legislators(self, **params):
        result = capitolwords._apicall(self, 'legislators', params)['results']
        return result

    def wordtree(self, **params):
        result = capitolwords._apicall(self, 'tree', params)['results']
        return result

    def text(self, **params):
        result = capitolwords._apicall(self, 'text', params)['results']
        return result

    def _similar(self, **params):
        result = capitolwords._apicall(self, '_similar', params)['results']
        return result
<commit_msg>Add similar-document handler back<commit_after>"""
    Python library for interacting with version 3 of the Capitol Words API

    Based heavily on the Sunlight Labs python-datacatalog wrapper:
    http://github.com/sunlightlabs/python-datacatalog/
"""

__author__ = "Joshua Ruihley <jruihley@sunlightfoundation.com>"
__version__ = "0.1"
__copyright__ = "Copyright (c) 2010 Sunlight Foundation"
__license__ = "BSD"

import urllib, httplib2
try:
    import json
except ImportError:
    import simplejson as json

class ApiError(Exception):
    """ Exception for API errors """

class capitolwords(object):

    def __init__(self, api_key=None, domain='capitolwords.org/api'):
        self.api_key = api_key
        self.domain = domain
        self.last_call = {}

    def store_last_call(self, url, params, response):
        self.last_call['url'] = url
        self.last_call['params'] = params
        self.last_call['response'] = response

    def _apicall(self, func, params=None, method='GET'):
        param_str = ''
        if params:
            params = dict([(k,v) for (k,v) in params.iteritems() if v is not None])
            param_str = '?%s' % urllib.urlencode(params)
        url = 'http://%s/%s.json%s' % (self.domain, func, param_str)
        print url

        try:
            h = httplib2.Http()
            response, content = h.request(url, method=method, headers=None, body=None)
            obj = json.loads(content)
            self.store_last_call(url, params, response)

            if 'errors' in obj:
                raise ApiError(obj['errors'], url, method, param_str)
            else:
                return obj
        except httplib2.HttpLib2Error, e:
            raise ApiError(e.read())
        except ValueError, e:
            raise ApiError('Invalid Response')

    def phrase_by_date_range(self, **params):
        result = capitolwords._apicall(self, 'dates', params)['results']
        return result

    def timeline(self, **params):
        result = capitolwords._apicall(self, 'chart/timeline', params)['results']
        return result

    def piechart(self, **params):
        result = capitolwords._apicall(self, 'chart/pie', params)['results']
        return result

    def phrase_by_entity_type(self, entity_type, **params):
        result = capitolwords._apicall(self, 'phrases/%s' % entity_type, params)['results']
        return result

    def top_phrases(self, **params):
        result = capitolwords._apicall(self, 'phrases', params)
        return result

    def get_legislator(self, **params):
        result = capitolwords._apicall(self, 'legislators', params)
        return result

    def legislators(self, **params):
        result = capitolwords._apicall(self, 'legislators', params)['results']
        return result

    def wordtree(self, **params):
        result = capitolwords._apicall(self, 'tree', params)['results']
        return result

    def text(self, **params):
        result = capitolwords._apicall(self, 'text', params)['results']
        return result

    def _similar(self, **params):
        result = capitolwords._apicall(self, '_similar', params)['results']
        return result

    def similar(self, **params):
        result = capitolwords._apicall(self, 'similar', params)['results']
        return result
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
Created on Sun Feb 28 15:56:10 2016

@author: John Swoboda
"""

import os, glob
import scipy as sp
import ConfigParser

import matplotlib
matplotlib.use('Agg') # for use where you're running on a command line
import pdb
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import pytz
from datetime import datetime
from dateutil import parser
from mpl_toolkits.basemap import Basemap
from GeoData.plotting import scatterGD, slice2DGD,insertinfo
from GeoData.GeoData import GeoData
from GeoData.utilityfuncs import readIonofiles, readAllskyFITS,readSRI_h5

INIOPTIONS = ['latbounds','lonbounds','timebounds','timewin','date','asgamma','aslim','gpslim','isrparams','paramlim','isrheight','reinterp','paramheight','ISRLatnum','ISRLonnum','wl']

class PlotClass(object):
    """ This class will handle """
    def __init__(self,inifile,GPSloc=None,ASloc=None,ISRloc=None):
        self.inifile = inifile
        self.params = readini(inifile)
        self.GDISR = None
        self.GDGPS = None
        self.GDAS = None

        #GeoData objects
        self.GPSRead(GPSloc)
        self.ASRead(ASloc)
        self.ISRRead(ISRloc)

        self.RegisterData()

    def GPSRead(self,GPSloc):
        if GPSloc is None:
            return

        timelim=self.params['timebounds']
        TEClist = []
        TECfiles = glob.glob(os.path.join(GPSloc,'*.iono'))
        TECtime = [sp.Inf,-sp.Inf];

        for ifile in TECfiles:
            TECGD = GeoData(readIonofiles,(ifile,))
            if timelim is not None:
                TECGD.timereduce(timelim)

            if len(TECGD.times)==0:
                continue
            TEClist.append(TECGD)
            TECtime[0] = min(min(TECGD.times[:,0]),TECtime[0])
            TECtime[1] = max(max(TECGD.times[:,0]),TECtime[1])

            self.GDGPS = TECGD

    def ASRead(self,ASloc):
        if ASloc is None:
            return

        wl = str(self.params['wl'])
        wlstr ='*_0'+wl+'_*.FITS'
        interpsavedfile = os.path.join(ASloc,'interp'+wl+'.h5')
        reinterp=self.params['reinterp']
        timelim=self.params['timebounds']
        if reinterp or (not os.path.isfile(interpsavedfile)):
            pfalla = sp.array([65.136667,-147.447222,689.])

            flist558 = glob.glob(os.path.join(ASloc,wlstr))
            allsky_data = GeoData(readAllskyFITS,(flist558,'PKR_20111006_AZ_10deg.FITS','PKR_20111006_EL_10deg.FITS',150.,pfalla))
            if timelim is not None:
                allsky_data.timereduce(timelim)

            xcoords = allsky_data.__changecoords__('WGS84')
            latlim=[xcoords[:,0].min(),xcoords[:,0].max()]
            lonlim=[xcoords[:,1].min(),xcoords[:,1].max()]
            nlat = 256
            nlon = 256

            latvec = sp.linspace(latlim[0],latlim[1],nlat)
            lonvec = sp.linspace(lonlim[0],lonlim[1],nlon)
            [LATM,LONM] = sp.meshgrid(latvec,lonvec)

            newcoords = sp.column_stack((LATM.flatten(),LONM.flatten(),150.*sp.ones(LONM.size)))
            allsky_data.interpolate(newcoords,'WGS84',method='linear',twodinterp=True)
            allsky_data.write_h5(interpsavedfile)
        else:
            allsky_data = GeoData.read_h5(interpsavedfile)
            if timelim is not None:
                allsky_data.timereduce(timelim)

        self.GDAS = allsky_data
    def ISRRead(self,ISRloc):

        if ISRloc is None:
            return

        pnheights= self.params['paramheight']
        paramstr = self.params['isrparams']
        SRIh5 = GeoData(readSRI_h5,(ISRloc,paramstr))
        dt1ts,dt2ts = self.params['timebounds']

        timelist = sp.where((SRIh5.times[:,0]>=dt1ts)&(SRIh5.times[:,0]<=dt2ts))[0]

        if len(timelist)==0:
            return

        SRIh5 = SRIh5.timeslice(timelist)

        hset = sp.array([i[1] for i in pnheights])
        uh,uhs =sp.unique(hset,return_inverse=True)

        newcoordname = 'WGS84'

        changed_coords = SRIh5.__changecoords__(newcoordname)

        latmin,latmax = [changed_coords[:,0].min(),changed_coords[:,0].max()]
        lonmin,lonmax = [changed_coords[:,1].min(),changed_coords[:,1].max()]
        latvec = sp.linspace(latmin,latmax,self.params['ISRLatnum'])
        lonvec = sp.linspace(lonmin,lonmax,self.params['ISRLonnum'])

        LON,LAT = sp.meshgrid(lonvec,latvec)
        xycoords = [LAT.flatten(),LON.flatten()]
            # interpolation
        ncoords = xycoords.shape[0]
        uhall = sp.repeat(uh,ncoords)

        coords = sp.tile(xycoords,(len(uh),1))
        coords = sp.column_stack((coords,uhall))

        SRIh5.interpolate(coords,newcoordname,method='linear')
        self.GDISR = SRIh5
    def RegisterData():
        """ """
    def writeini(self,fname):
        params=self.params

        cfgfile = open(fname,'w')
        config = ConfigParser.ConfigParser(allow_no_value = True)

        config.add_section('params')
        config.add_section('paramsnames')
        for ip in INIOPTIONS:

            if ip=='timebounds':
                dts = map(datetime.utcfromtimestamp, params[ip])
                data = datetime.strftime('%m/%d/%Y %H:%M:%S',dts[0]) + ' ' + datetime.strftime('%m/%d/%Y %H:%M:%S',dts[1])
                config.set('params',ip,data)
            elif ip=='paramheight':
                temp= [item for sublist in params['paramheight'] for item in sublist]
                data = ""
                for a in temp[ip]:
                    data += str(a)
                    data += " "
                config.set('params',ip,data)
            elif ip=='reinterp':
                if params[ip]:
                    data='Yes'
                else:
                    data='No'
                config.set('params',ip,data)
            elif type(params[ip]) in(sp.ndarray,list):
                data = ""
                for a in params[ip]:
                    data += str(a)
                    data += " "
                config.set('params',ip,data)
            else:
                config.set('params',ip,str(params[ip]))
            config.set('paramsnames',ip,ip)
        config.write(cfgfile)
        cfgfile.close()

def readini(inifile):

    config = ConfigParser.ConfigParser()
    config.read(inifile)
    params={i:None for i in INIOPTIONS}
    # Read in data from ini file
    for ip in config.options('params'):
        # get the original param name
        rname  = config.get('paramsnames',ip)
        # get the parameter and split it up
        params[rname] = config.get('params',ip)
        params[rname]=params[rname].split(" ")
        # If its a single object try to
        if len(params[rname])==1:
            params[rname]=params[rname][0]
            try:
                params[rname]=float(params[rname])
            except:
                pass
        else:
            for a in range(len(params[rname])):
                try:
                    params[rname][a]=float(params[rname][a])
                except:
                    pass

    # turn the time bounds to time stamps
    if not params['timebounds']is None:
        timelist = params['timebounds']
        (dt1,dt2) = parser.parse(timelist[0]+ ' '+timelist[1]),parser.parse(timelist[2]+ ' '+timelist[3])
        dt1 =dt1.replace(tzinfo=pytz.utc)
        dt2 = dt2.replace(tzinfo=pytz.utc)
        dt1ts = (dt1 -datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()
        dt2ts = (dt2 -datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()
        params['timebounds']=[dt1ts,dt2ts]
    # change param height to a list of lists
    if not params['paramheight'] is None:
        l1 = params['paramheight'][::2]
        l2 = params['paramheight'][1::2]
        params['paramheight']=[[i,j] for i,j in zip(l1,l2)]
    # Default for reinterp is false
    if params['reinterp']is None:
        params['reinterp']=False
    else:
        params['reinterp'] = params['reinterp'].lower()=='yes'
    return params<commit_msg>PlottingClass.py update may not work though<commit_after>#!/usr/bin/env python
"""
Created on Sun Feb 28 15:56:10 2016

@author: John Swoboda
"""

import os, glob
import scipy as sp
import ConfigParser

import matplotlib
matplotlib.use('Agg') # for use where you're running on a command line
import pdb
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import pytz
from datetime import datetime
from dateutil import parser
from mpl_toolkits.basemap import Basemap
from GeoData.plotting import scatterGD, slice2DGD,insertinfo
from GeoData.GeoData import GeoData
from GeoData.utilityfuncs import readIonofiles, readAllskyFITS,readSRI_h5

INIOPTIONS = ['latbounds','lonbounds','timebounds','timewin','date','asgamma','aslim','gpslim','isrparams','paramlim','isrheight','reinterp','paramheight','ISRLatnum','ISRLonnum','wl']

class PlotClass(object):
    """ This class will handle """
    def __init__(self,inifile,GPSloc=None,ASloc=None,ISRloc=None):
        self.inifile = inifile
        self.params = readini(inifile)
        self.GDISR = None
        self.GDGPS = None
        self.GDAS = None

        #GeoData objects
        self.GPSRead(GPSloc)
        self.ASRead(ASloc)
        self.ISRRead(ISRloc)

        self.RegisterData()

    def GPSRead(self,GPSloc):
        if GPSloc is None:
            return

        timelim=self.params['timebounds']
        TEClist = []
        TECfiles = glob.glob(os.path.join(GPSloc,'*.iono'))
        TECtime = [sp.Inf,-sp.Inf];

        for ifile in TECfiles:
            TECGD = GeoData(readIonofiles,(ifile,))
            if timelim is not None:
                TECGD.timereduce(timelim)

            if len(TECGD.times)==0:
                continue
            TEClist.append(TECGD)
            TECtime[0] = min(min(TECGD.times[:,0]),TECtime[0])
            TECtime[1] = max(max(TECGD.times[:,0]),TECtime[1])

            self.GDGPS = TECGD

    def ASRead(self,ASloc):
        if ASloc is None:
            return

        wl = str(self.params['wl'])
        wlstr ='*_0'+wl+'_*.FITS'
        interpsavedfile = os.path.join(ASloc,'interp'+wl+'.h5')
        reinterp=self.params['reinterp']
        timelim=self.params['timebounds']
        if reinterp or (not os.path.isfile(interpsavedfile)):
            pfalla = sp.array([65.136667,-147.447222,689.])

            flist558 = glob.glob(os.path.join(ASloc,wlstr))
            allsky_data = GeoData(readAllskyFITS,(flist558,'PKR_20111006_AZ_10deg.FITS','PKR_20111006_EL_10deg.FITS',150.,pfalla))
            if timelim is not None:
                allsky_data.timereduce(timelim)

            xcoords = allsky_data.__changecoords__('WGS84')
            latlim=[xcoords[:,0].min(),xcoords[:,0].max()]
            lonlim=[xcoords[:,1].min(),xcoords[:,1].max()]
            nlat = 256
            nlon = 256

            latvec = sp.linspace(latlim[0],latlim[1],nlat)
            lonvec = sp.linspace(lonlim[0],lonlim[1],nlon)
            [LATM,LONM] = sp.meshgrid(latvec,lonvec)

            newcoords = sp.column_stack((LATM.flatten(),LONM.flatten(),150.*sp.ones(LONM.size)))
            allsky_data.interpolate(newcoords,'WGS84',method='linear',twodinterp=True)
            allsky_data.write_h5(interpsavedfile)
        else:
            allsky_data = GeoData.read_h5(interpsavedfile)
            if timelim is not None:
                allsky_data.timereduce(timelim)

        self.GDAS = allsky_data
    def ISRRead(self,ISRloc):

        if ISRloc is None:
            return

        pnheights= self.params['paramheight']
        paramstr = self.params['isrparams']
        SRIh5 = GeoData(readSRI_h5,(ISRloc,paramstr))
        dt1ts,dt2ts = self.params['timebounds']

        timelist = sp.where((SRIh5.times[:,0]>=dt1ts)&(SRIh5.times[:,0]<=dt2ts))[0]

        if len(timelist)==0:
            return

        SRIh5 = SRIh5.timeslice(timelist)

        hset = sp.array([i[1] for i in pnheights])
        uh,uhs =sp.unique(hset,return_inverse=True)

        newcoordname = 'WGS84'

        changed_coords = SRIh5.__changecoords__(newcoordname)

        latmin,latmax = [changed_coords[:,0].min(),changed_coords[:,0].max()]
        lonmin,lonmax = [changed_coords[:,1].min(),changed_coords[:,1].max()]
        latvec = sp.linspace(latmin,latmax,self.params['ISRLatnum'])
        lonvec = sp.linspace(lonmin,lonmax,self.params['ISRLonnum'])

        LON,LAT = sp.meshgrid(lonvec,latvec)
        xycoords = [LAT.flatten(),LON.flatten()]
            # interpolation
        ncoords = xycoords.shape[0]
        uhall = sp.repeat(uh,ncoords)

        coords = sp.tile(xycoords,(len(uh),1))
        coords = sp.column_stack((coords,uhall))

        SRIh5.interpolate(coords,newcoordname,method='linear')
        self.GDISR = SRIh5
    def plotmap(self,fig,ax):

        latlim2 = self.params['latbounds']
        lonlim2 = self.params['lonbounds']
        m = Basemap(projection='merc',lon_0=sp.mean(lonlim2),lat_0=sp.mean(latlim2),\
        lat_ts=sp.mean(latlim2),llcrnrlat=latlim2[0],urcrnrlat=latlim2[1],\
        llcrnrlon=lonlim2[0],urcrnrlon=lonlim2[1],\
        rsphere=6371200.,resolution='i',ax=ax)
        # draw coastlines, state and country boundaries, edge of map.
        #m.drawcoastlines()
    #    m.drawstates()
    #    m.drawcountries()
        shp_info = m.readshapefile('st99_d00','states',drawbounds=True)

        merstep = sp.round_((lonlim2[1]-lonlim2[0])/5.)
        parstep = sp.round_((latlim2[1]-latlim2[0])/5.)
        meridians=sp.arange(lonlim2[0],lonlim2[1],merstep)
        parallels = sp.arange(latlim2[0],latlim2[1],parstep)
        parhand=m.drawparallels(parallels,labels=[1,0,0,0],fontsize=10)
        mrdhand = m.drawmeridians(meridians,labels=[0,0,0,1],fontsize=10)
        plt.hold(True)
        return m

    def plotalldata(self,plotdir,plotdir,m,ax,fig,):
        """ """

    def plotsingle(self,m,ax,fig,tgps = 0,tas=0,tisr=0):
    """ Make a set of plots when given both all sky ad GPS are given.
        Inputs
            allsky_data - The all sky data as a GeoData object.
            TEClist - The of GeoData objects derived from the ionofiles.
            allskylist - A list of list which determines which allsky times are used."""
    maxplot = len(allsky_data.times)
    maxplot = sp.array([len(i) for i in allskylist]).sum()
    strlen = int(sp.ceil(sp.log10(maxplot))+1)
    fmstr = '{0:0>'+str(strlen)+'}_'
    plotnum=0
    firstbar = True
    optbnds = [300,1100]
    for (optic_times,gps_cur)in zip(allskylist,gpslist):
        gpshands = []
        gpsmin = sp.inf
        gpsmax = -sp.inf
        for igpsn, (igps,igpslist) in enumerate(zip(TEClist,gps_cur)):
            print('Plotting GPS data from rec {0} of {1}'.format(igpsn,len(gps_cur)))
            # check if there's anything to plot
            if len(igpslist)==0:
                continue

            (sctter,scatercb) = scatterGD(igps,'alt',3.5e5,vbounds=[0,20],time = igpslist,gkey = 'vTEC',cmap='plasma',fig=fig,
                  ax=ax,title='',cbar=True,err=.1,m=m)
            gpsmin = sp.minimum(igps.times[igpslist,0].min(),gpsmin)
            gpsmax = sp.maximum(igps.times[igpslist,0].max(),gpsmax)
            gpshands.append(sctter)
        scatercb.set_label('vTEC in TECu')
        #change he z order
        minz = gpshands[0].get_zorder()
        for i in reversed(gpshands):
            i.set_zorder(i.get_zorder()+1)

        for iop in optic_times:
            (slice3,cbar3) = slice2DGD(allsky_data,'alt',150,optbnds,title='',
                                time = iop,cmap='gray',gkey = 'image',fig=fig,ax=ax,cbar=False,m=m)
            slice3.set_norm(colors.PowerNorm(gamma=0.6,vmin=optbnds[0],vmax=optbnds[1]))

            if firstbar:
                firstbar=False
                cbaras = plt.colorbar(slice3,ax=ax,orientation='horizontal')
                cbaras.set_label('All Sky Scale')
            slice3.set_zorder(minz)
            plt.title(insertinfo('GPS $tmdy $thmsehms',posix=gpsmin,posixend=gpsmax)+'\n'+insertinfo('All Sky $tmdy $thmsehms',posix=allsky_data.times[iop,0],posixend=allsky_data.times[iop,1]))
            print('Ploting {0} of {1} plots'.format(plotnum,maxplot))
            plt.savefig(os.path.join(plotdir,fmstr.format(plotnum)+'ASwGPS.png'))

            plotnum+=1
            slice3.remove()
        for i in reversed(gpshands):
            i.remove()
    def RegisterData(self):
        """ """
        tbounds = self.params['timebounds']
        #%% make lists for plotting
        tectime = sp.arange(tbounds[0],tbounds[1],60.*tint)
        nptimes= len(tectime)

        if (not self.GDAS is None):
            GPS2AS=[[]]*nptimes-1
            allskytime=self.GDAS.times[:,0]

            if (not self.GDISR is None):
                as2radar =GDAS.timeregister(self.GDISR)
            for itasn in range(len(techtime)-1)
                itback=tectime[itasn]
                itfor = tectime[itasn+1]
                itas = sp.where(sp.logical_and(allskytime>=itback, allskytime<itfor))[0]
                if len(itas)==0:
                    itas = sp.where(allskytime<=itback)[0]
                    if len(itas)==0:
                        continue
                    itas = [itas[-1]]
                GPS2AS[itasn] = itas
            elif (not self.GDISR is None):
                GPS2AS=[[]]*nptimes-1
                allskytime=self.GDISR.times

                for itasn in range(len(techtime)-1)
                    itback=tectime[itasn]
                    itfor = tectime[itasn+1]
                    #need to fix this
                    itas = sp.where(sp.logical_and(allskytime[:,1]>=itback, allskytime[:,0]<itfor))[0]
                    if len(itas)==0:
                        itas = sp.where(allskytime<=itback)[0]
                        if len(itas)==0:
                            continue
                        itas = [itas[-1]]
                    GPS2AS[itasn] = itas
    def writeini(self,fname):
        params=self.params

        cfgfile = open(fname,'w')
        config = ConfigParser.ConfigParser(allow_no_value = True)

        config.add_section('params')
        config.add_section('paramsnames')
        for ip in INIOPTIONS:

            if ip=='timebounds':
                dts = map(datetime.utcfromtimestamp, params[ip])
                data = datetime.strftime('%m/%d/%Y %H:%M:%S',dts[0]) + ' ' + datetime.strftime('%m/%d/%Y %H:%M:%S',dts[1])
                config.set('params',ip,data)
            elif ip=='paramheight':
                temp= [item for sublist in params['paramheight'] for item in sublist]
                data = ""
                for a in temp[ip]:
                    data += str(a)
                    data += " "
                config.set('params',ip,data)
            elif ip=='reinterp':
                if params[ip]:
                    data='Yes'
                else:
                    data='No'
                config.set('params',ip,data)
            elif type(params[ip]) in(sp.ndarray,list):
                data = ""
                for a in params[ip]:
                    data += str(a)
                    data += " "
                config.set('params',ip,data)
            else:
                config.set('params',ip,str(params[ip]))
            config.set('paramsnames',ip,ip)
        config.write(cfgfile)
        cfgfile.close()

def readini(inifile):

    config = ConfigParser.ConfigParser()
    config.read(inifile)
    params={i:None for i in INIOPTIONS}
    # Read in data from ini file
    for ip in config.options('params'):
        # get the original param name
        rname  = config.get('paramsnames',ip)
        # get the parameter and split it up
        params[rname] = config.get('params',ip)
        params[rname]=params[rname].split(" ")
        # If its a single object try to
        if len(params[rname])==1:
            params[rname]=params[rname][0]
            try:
                params[rname]=float(params[rname])
            except:
                pass
        else:
            for a in range(len(params[rname])):
                try:
                    params[rname][a]=float(params[rname][a])
                except:
                    pass

    # turn the time bounds to time stamps
    if not params['timebounds']is None:
        timelist = params['timebounds']
        (dt1,dt2) = parser.parse(timelist[0]+ ' '+timelist[1]),parser.parse(timelist[2]+ ' '+timelist[3])
        dt1 =dt1.replace(tzinfo=pytz.utc)
        dt2 = dt2.replace(tzinfo=pytz.utc)
        dt1ts = (dt1 -datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()
        dt2ts = (dt2 -datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()
        params['timebounds']=[dt1ts,dt2ts]
    # change param height to a list of lists
    if not params['paramheight'] is None:
        l1 = params['paramheight'][::2]
        l2 = params['paramheight'][1::2]
        params['paramheight']=[[i,j] for i,j in zip(l1,l2)]
    # Default for reinterp is false
    if params['reinterp']is None:
        params['reinterp']=False
    else:
        params['reinterp'] = params['reinterp'].lower()=='yes'
    return params<|endoftext|>


<commit_before>import requests
from   pyquery import PyQuery as pq

def normalStyle(types, names, escape = False):
	padTo = 0
	for t in types:
		# Find out which has the longest
		tempLen = len(t)
		if tempLen > padTo:
			padTo = tempLen
	if escape:
		partdown = '\`\`\`\n'
	else:
		partdown = '```\n'
	for i in range(0, len(types)):
		partdown += types[i].rjust(padTo, ' ') + ' : ' + names[i] + '\n'
	if escape:
		partdown += '\`\`\`'
	else:
		partdown += '```'
	return partdown

def mdStyle(types, names, escape = False):
	padTo = 0
	for t in types:
		# Find out which has the longest
		ty = "<" + t.replace(' ', '-') + ":"
		tempLen = len(ty)
		if tempLen > padTo:
			padTo = tempLen
	if escape:
		partdown = '\`\`\`md\n'
	else:
		partdown = '```md\n'
	for i in range(0, len(types)):
		t = "<" + types[i].replace(' ', '-') + ":"
		partdown += t.ljust(padTo, ' ') + " " + names[i] + '>\n'
	if escape:
		partdown += '\`\`\`'
	else:
		partdown += '```'
	return partdown

def mdBlockStyle(types, names, escape = False):
	padTo = 0
	for t in types:
		# Find out which has the longest
		ty = "[" + t
		tempLen = len(ty)
		if tempLen > padTo:
			padTo = tempLen
	if escape:
		partdown = '\`\`\`md\n'
	else:
		partdown = '```md\n'
	for i in range(0, len(types)):
		ty = "[" + types[i]
		t = "| " + ty.rjust(padTo, ' ') + "]["
		partdown += t.rjust(padTo, ' ') + names[i] + ']\n'
	if escape:
		partdown += '\`\`\`'
	else:
		partdown += '```'
	return partdown

def boldStyle(types, names, escape = False):
	partdown = ''
	for i in range(0, len(types)):
		if escape:
			partdown += "\*\*" + types[i] + ":\*\* " + names[i] + '\n'
		else:
			partdown += "**" + types[i] + ":** " + names[i] + '\n'
	partdown = partdown[:-1]
	return partdown

def boldItalicStyle(types, names, escape = False):
	partdown = ''
	for i in range(0, len(types)):
		if escape:
			partdown += "\*\*\*" + types[i] + ":\*\*\* \*" + names[i] + '\*\n'
		else:
			partdown += "***" + types[i] + ":*** *" + names[i] + '*\n'
	partdown = partdown[:-1]
	return partdown

def getMarkdown( url, style = None, escape = False):
	# Ensure we're using a list
	url = url.replace('/b/', '/list/')
	if not style:
		style = 'normal'
	try:
		response = requests.get(url)
	except Exception:
		return None
	dom = pq(response.text)

	# Experimental crap because developing while not at home
	table = dom('table.manual-zebra').children('tbody')
	for i in range(0, len(table)):
		child = table.eq(i)
		print(child)
		try:
			children = child.children()
		except AttributeError:
			continue
		print(children)
		print(len(children))
		#type = children[0].text_content().strip().replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		#name = children[2].text_content().strip().replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		#print('Type: "{}"\nName: "{}"'.format(type, name))

	names = []
	types = []
	for e in dom('td.component-type.tl'):
		text = e.text_content().strip()
		text = text.replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		text = ' '.join(text.split())
		if text == "":
			if not len(types):
				# Nothing yet - this is weird
				text = '-'
			else:
				text = types[len(types)-1]
		types.append(text)
	for e in dom('td.component-name.tl'):
		text = e.text_content().strip()
		text = text.replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		text = ' '.join(text.split())
		names.append(text)
	if not len(types):
		return None
	if not len(types) == len(names):
		# Only way this would happen that I've seen so far, is with custom entries
		return 'custom'
	partout = ''
	if style.lower() == 'md':
		partout = mdStyle(types, names, escape)
	elif style.lower() == 'mdblock':
		partout = mdBlockStyle(types, names, escape)
	elif style.lower() == 'bold':
		partout = boldStyle(types, names, escape)
	elif style.lower() == 'bolditalic':
		partout = boldItalicStyle(types, names, escape)
	else:
		partout = normalStyle(types, names, escape)
	return partout
<commit_msg>Update PCPP.py<commit_after>import requests
from   pyquery import PyQuery as pq

def normalStyle(types, names, escape = False):
	padTo = 0
	for t in types:
		# Find out which has the longest
		tempLen = len(t)
		if tempLen > padTo:
			padTo = tempLen
	if escape:
		partdown = '\`\`\`\n'
	else:
		partdown = '```\n'
	for i in range(0, len(types)):
		partdown += types[i].rjust(padTo, ' ') + ' : ' + names[i] + '\n'
	if escape:
		partdown += '\`\`\`'
	else:
		partdown += '```'
	return partdown

def mdStyle(types, names, escape = False):
	padTo = 0
	for t in types:
		# Find out which has the longest
		ty = "<" + t.replace(' ', '-') + ":"
		tempLen = len(ty)
		if tempLen > padTo:
			padTo = tempLen
	if escape:
		partdown = '\`\`\`md\n'
	else:
		partdown = '```md\n'
	for i in range(0, len(types)):
		t = "<" + types[i].replace(' ', '-') + ":"
		partdown += t.ljust(padTo, ' ') + " " + names[i] + '>\n'
	if escape:
		partdown += '\`\`\`'
	else:
		partdown += '```'
	return partdown

def mdBlockStyle(types, names, escape = False):
	padTo = 0
	for t in types:
		# Find out which has the longest
		ty = "[" + t
		tempLen = len(ty)
		if tempLen > padTo:
			padTo = tempLen
	if escape:
		partdown = '\`\`\`md\n'
	else:
		partdown = '```md\n'
	for i in range(0, len(types)):
		ty = "[" + types[i]
		t = "| " + ty.rjust(padTo, ' ') + "]["
		partdown += t.rjust(padTo, ' ') + names[i] + ']\n'
	if escape:
		partdown += '\`\`\`'
	else:
		partdown += '```'
	return partdown

def boldStyle(types, names, escape = False):
	partdown = ''
	for i in range(0, len(types)):
		if escape:
			partdown += "\*\*" + types[i] + ":\*\* " + names[i] + '\n'
		else:
			partdown += "**" + types[i] + ":** " + names[i] + '\n'
	partdown = partdown[:-1]
	return partdown

def boldItalicStyle(types, names, escape = False):
	partdown = ''
	for i in range(0, len(types)):
		if escape:
			partdown += "\*\*\*" + types[i] + ":\*\*\* \*" + names[i] + '\*\n'
		else:
			partdown += "***" + types[i] + ":*** *" + names[i] + '*\n'
	partdown = partdown[:-1]
	return partdown

def getMarkdown( url, style = None, escape = False):
	# Ensure we're using a list
	url = url.replace('/b/', '/list/')
	if not style:
		style = 'normal'
	try:
		response = requests.get(url)
	except Exception:
		return None
	dom = pq(response.text)

	# Experimental crap because developing while not at home
	table = dom('table.manual-zebra').children('tbody').children()
	for i in range(0, len(table)):
		child = table.eq(i)
		print(child)
		try:
			children = child.children()
		except AttributeError:
			continue
		print(children)
		print(len(children))
		#type = children[0].text_content().strip().replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		#name = children[2].text_content().strip().replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		#print('Type: "{}"\nName: "{}"'.format(type, name))

	names = []
	types = []
	for e in dom('td.component-type.tl'):
		text = e.text_content().strip()
		text = text.replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		text = ' '.join(text.split())
		if text == "":
			if not len(types):
				# Nothing yet - this is weird
				text = '-'
			else:
				text = types[len(types)-1]
		types.append(text)
	for e in dom('td.component-name.tl'):
		text = e.text_content().strip()
		text = text.replace('\r', '').replace('\n', ' ').replace('\t', ' ')
		text = ' '.join(text.split())
		names.append(text)
	if not len(types):
		return None
	if not len(types) == len(names):
		# Only way this would happen that I've seen so far, is with custom entries
		return 'custom'
	partout = ''
	if style.lower() == 'md':
		partout = mdStyle(types, names, escape)
	elif style.lower() == 'mdblock':
		partout = mdBlockStyle(types, names, escape)
	elif style.lower() == 'bold':
		partout = boldStyle(types, names, escape)
	elif style.lower() == 'bolditalic':
		partout = boldItalicStyle(types, names, escape)
	else:
		partout = normalStyle(types, names, escape)
	return partout
<|endoftext|>


<commit_before>import pytest
import numpy as np
from numpy.testing import assert_array_almost_equal, assert_array_equal

import dask
import dask.array as da
from dask.array.ghost import (Array, fractional_slice, getitem, trim_internal,
                              ghost_internal, nearest, constant, boundaries,
                              reflect, periodic, ghost)
from dask.core import get

def eq(a, b):
    if isinstance(a, Array):
        a = a.compute(get=dask.get)
    if isinstance(b, Array):
        b = b.compute(get=dask.get)
    c = a == b
    if isinstance(c, np.ndarray):
        c = c.all()
    return c

def test_fractional_slice():
    assert fractional_slice(('x', 4.9), {0: 2}) == \
            (getitem, ('x', 5), (slice(0, 2),))

    assert fractional_slice(('x', 3, 5.1), {0: 2, 1: 3}) == \
            (getitem, ('x', 3, 5), (slice(None, None, None), slice(-3, None)))

    assert fractional_slice(('x', 2.9, 5.1), {0: 2, 1: 3}) == \
            (getitem, ('x', 3, 5), (slice(0, 2), slice(-3, None)))

def test_ghost_internal():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    g = ghost_internal(d, {0: 2, 1: 1})
    result = g.compute(get=get)
    assert g.chunks == ((6, 6), (5, 5))

    expected = np.array([
        [ 0,  1,  2,  3,  4,    3,  4,  5,  6,  7],
        [ 8,  9, 10, 11, 12,   11, 12, 13, 14, 15],
        [16, 17, 18, 19, 20,   19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28,   27, 28, 29, 30, 31],
        [32, 33, 34, 35, 36,   35, 36, 37, 38, 39],
        [40, 41, 42, 43, 44,   43, 44, 45, 46, 47],

        [16, 17, 18, 19, 20,   19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28,   27, 28, 29, 30, 31],
        [32, 33, 34, 35, 36,   35, 36, 37, 38, 39],
        [40, 41, 42, 43, 44,   43, 44, 45, 46, 47],
        [48, 49, 50, 51, 52,   51, 52, 53, 54, 55],
        [56, 57, 58, 59, 60,   59, 60, 61, 62, 63]])

    assert eq(result, expected)

def test_trim_internal():
    d = da.ones((40, 60), chunks=(10, 10))
    e = trim_internal(d, axes={0: 1, 1: 2})

    assert e.chunks == ((8, 8, 8, 8), (6, 6, 6, 6, 6, 6))

def test_periodic():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    e = periodic(d, axis=0, depth=2)
    assert e.shape[0] == d.shape[0] + 4
    assert e.shape[1] == d.shape[1]

    assert eq(e[1, :], d[-1, :])
    assert eq(e[0, :], d[-2, :])

def test_reflect():
    x = np.arange(10)
    d = da.from_array(x, chunks=(5, 5))

    e = reflect(d, axis=0, depth=2)
    expected = np.array([1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8])
    assert eq(e, expected)

    e = reflect(d, axis=0, depth=1)
    expected = np.array([0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9])
    assert eq(e, expected)

def test_nearest():
    x = np.arange(10)
    d = da.from_array(x, chunks=(5, 5))

    e = nearest(d, axis=0, depth=2)
    expected = np.array([0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9])
    assert eq(e, expected)

    e = nearest(d, axis=0, depth=1)
    expected = np.array([0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9])
    assert eq(e, expected)

def test_constant():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    e = constant(d, axis=0, depth=2, value=10)
    assert e.shape[0] == d.shape[0] + 4
    assert e.shape[1] == d.shape[1]

    assert eq(e[1, :], 10)
    assert eq(e[-1, :], 10)

def test_boundaries():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    e = boundaries(d, {0: 2, 1: 1}, {0: 0, 1: 'periodic'})

    expected = np.array(
        [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [ 7, 0, 1, 2, 3, 4, 5, 6, 7, 0],
         [15, 8, 9,10,11,12,13,14,15, 8],
         [23,16,17,18,19,20,21,22,23,16],
         [31,24,25,26,27,28,29,30,31,24],
         [39,32,33,34,35,36,37,38,39,32],
         [47,40,41,42,43,44,45,46,47,40],
         [55,48,49,50,51,52,53,54,55,48],
         [63,56,57,58,59,60,61,62,63,56],
         [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
    assert eq(e, expected)

def test_ghost():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))
    g = ghost(d, depth={0: 2, 1: 1}, boundary={0: 100, 1: 'reflect'})
    assert g.chunks == ((8, 8), (6, 6))
    expected = np.array(
      [[100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
       [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
       [  0,   0,   1,   2,   3,   4,   3,   4,   5,   6,   7,   7],
       [  8,   8,   9,  10,  11,  12,  11,  12,  13,  14,  15,  15],
       [ 16,  16,  17,  18,  19,  20,  19,  20,  21,  22,  23,  23],
       [ 24,  24,  25,  26,  27,  28,  27,  28,  29,  30,  31,  31],
       [ 32,  32,  33,  34,  35,  36,  35,  36,  37,  38,  39,  39],
       [ 40,  40,  41,  42,  43,  44,  43,  44,  45,  46,  47,  47],
       [ 16,  16,  17,  18,  19,  20,  19,  20,  21,  22,  23,  23],
       [ 24,  24,  25,  26,  27,  28,  27,  28,  29,  30,  31,  31],
       [ 32,  32,  33,  34,  35,  36,  35,  36,  37,  38,  39,  39],
       [ 40,  40,  41,  42,  43,  44,  43,  44,  45,  46,  47,  47],
       [ 48,  48,  49,  50,  51,  52,  51,  52,  53,  54,  55,  55],
       [ 56,  56,  57,  58,  59,  60,  59,  60,  61,  62,  63,  63],
       [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
       [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]])
    assert eq(g, expected)

    g = ghost(d, depth={0: 2, 1: 1}, boundary={0: 100})
    assert g.chunks == ((8, 8), (5, 5))

def test_map_overlap():
    x = da.arange(10, chunks=5)

    y = x.map_overlap(lambda x: x + len(x), depth=2)
    assert eq(y, np.arange(10) + 5 + 2 + 2)

def test_nearest_ghost():
    a = np.arange(144).reshape(12, 12).astype(float)

    darr = da.from_array(a, chunks=(6, 6))
    garr = ghost(darr, depth={0: 5, 1: 5},
                 boundary={0: 'nearest', 1: 'nearest'})
    tarr = trim_internal(garr, {0: 5, 1: 5})
    assert_array_almost_equal(tarr, a)

def test_0_depth():
    expected = np.arange(100).reshape(10, 10)
    darr = da.from_array(expected, chunks=(5, 2))

    depth = {0: 0, 1: 0}

    reflected = ghost(darr, depth=depth, boundary='reflect')
    nearest = ghost(darr, depth=depth, boundary='nearest')
    periodic = ghost(darr, depth=depth, boundary='periodic')
    constant = ghost(darr, depth=depth, boundary=42)

    result = trim_internal(reflected, depth)
    assert_array_equal(result, expected)

    result = trim_internal(nearest, depth)
    assert_array_equal(result, expected)

    result = trim_internal(periodic, depth)
    assert_array_equal(result, expected)

    result = trim_internal(constant, depth)
    assert_array_equal(result, expected)

def test_depth_equals_boundary_length():
    expected = np.arange(100).reshape(10, 10)
    darr = da.from_array(expected, chunks=(5, 5))

    depth = {0: 5, 1: 5}

    reflected = ghost(darr, depth=depth, boundary='reflect')
    nearest = ghost(darr, depth=depth, boundary='nearest')
    periodic = ghost(darr, depth=depth, boundary='periodic')
    constant = ghost(darr, depth=depth, boundary=42)

    result = trim_internal(reflected, depth)
    assert_array_equal(result, expected)

    result = trim_internal(nearest, depth)
    assert_array_equal(result, expected)

    result = trim_internal(periodic, depth)
    assert_array_equal(result, expected)

    result = trim_internal(constant, depth)
    assert_array_equal(result, expected)

@pytest.mark.xfail
def test_depth_greater_than_boundary_length():
    expected = np.arange(100).reshape(10, 10)
    darr = da.from_array(expected, chunks=(5, 5))

    depth = {0: 8, 1: 7}

    reflected = ghost(darr, depth=depth, boundary='reflect')
    nearest = ghost(darr, depth=depth, boundary='nearest')
    periodic = ghost(darr, depth=depth, boundary='periodic')
    constant = ghost(darr, depth=depth, boundary=42)

    result = trim_internal(reflected, depth)
    assert_array_equal(result, expected)

    result = trim_internal(nearest, depth)
    assert_array_equal(result, expected)

    result = trim_internal(periodic, depth)
    assert_array_equal(result, expected)

    result = trim_internal(constant, depth)
    assert_array_equal(result, expected)
<commit_msg>Add failing tests for some depth=0 others nonzero<commit_after>import pytest
import numpy as np
from numpy.testing import assert_array_almost_equal, assert_array_equal

import dask
import dask.array as da
from dask.array.ghost import (Array, fractional_slice, getitem, trim_internal,
                              ghost_internal, nearest, constant, boundaries,
                              reflect, periodic, ghost)
from dask.core import get

def eq(a, b):
    if isinstance(a, Array):
        a = a.compute(get=dask.get)
    if isinstance(b, Array):
        b = b.compute(get=dask.get)
    c = a == b
    if isinstance(c, np.ndarray):
        c = c.all()
    return c

def test_fractional_slice():
    assert fractional_slice(('x', 4.9), {0: 2}) == \
            (getitem, ('x', 5), (slice(0, 2),))

    assert fractional_slice(('x', 3, 5.1), {0: 2, 1: 3}) == \
            (getitem, ('x', 3, 5), (slice(None, None, None), slice(-3, None)))

    assert fractional_slice(('x', 2.9, 5.1), {0: 2, 1: 3}) == \
            (getitem, ('x', 3, 5), (slice(0, 2), slice(-3, None)))

def test_ghost_internal():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    g = ghost_internal(d, {0: 2, 1: 1})
    result = g.compute(get=get)
    assert g.chunks == ((6, 6), (5, 5))

    expected = np.array([
        [ 0,  1,  2,  3,  4,    3,  4,  5,  6,  7],
        [ 8,  9, 10, 11, 12,   11, 12, 13, 14, 15],
        [16, 17, 18, 19, 20,   19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28,   27, 28, 29, 30, 31],
        [32, 33, 34, 35, 36,   35, 36, 37, 38, 39],
        [40, 41, 42, 43, 44,   43, 44, 45, 46, 47],

        [16, 17, 18, 19, 20,   19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28,   27, 28, 29, 30, 31],
        [32, 33, 34, 35, 36,   35, 36, 37, 38, 39],
        [40, 41, 42, 43, 44,   43, 44, 45, 46, 47],
        [48, 49, 50, 51, 52,   51, 52, 53, 54, 55],
        [56, 57, 58, 59, 60,   59, 60, 61, 62, 63]])

    assert eq(result, expected)

def test_trim_internal():
    d = da.ones((40, 60), chunks=(10, 10))
    e = trim_internal(d, axes={0: 1, 1: 2})

    assert e.chunks == ((8, 8, 8, 8), (6, 6, 6, 6, 6, 6))

def test_periodic():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    e = periodic(d, axis=0, depth=2)
    assert e.shape[0] == d.shape[0] + 4
    assert e.shape[1] == d.shape[1]

    assert eq(e[1, :], d[-1, :])
    assert eq(e[0, :], d[-2, :])

def test_reflect():
    x = np.arange(10)
    d = da.from_array(x, chunks=(5, 5))

    e = reflect(d, axis=0, depth=2)
    expected = np.array([1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8])
    assert eq(e, expected)

    e = reflect(d, axis=0, depth=1)
    expected = np.array([0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9])
    assert eq(e, expected)

def test_nearest():
    x = np.arange(10)
    d = da.from_array(x, chunks=(5, 5))

    e = nearest(d, axis=0, depth=2)
    expected = np.array([0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9])
    assert eq(e, expected)

    e = nearest(d, axis=0, depth=1)
    expected = np.array([0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9])
    assert eq(e, expected)

def test_constant():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    e = constant(d, axis=0, depth=2, value=10)
    assert e.shape[0] == d.shape[0] + 4
    assert e.shape[1] == d.shape[1]

    assert eq(e[1, :], 10)
    assert eq(e[-1, :], 10)

def test_boundaries():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))

    e = boundaries(d, {0: 2, 1: 1}, {0: 0, 1: 'periodic'})

    expected = np.array(
        [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [ 7, 0, 1, 2, 3, 4, 5, 6, 7, 0],
         [15, 8, 9,10,11,12,13,14,15, 8],
         [23,16,17,18,19,20,21,22,23,16],
         [31,24,25,26,27,28,29,30,31,24],
         [39,32,33,34,35,36,37,38,39,32],
         [47,40,41,42,43,44,45,46,47,40],
         [55,48,49,50,51,52,53,54,55,48],
         [63,56,57,58,59,60,61,62,63,56],
         [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
    assert eq(e, expected)

def test_ghost():
    x = np.arange(64).reshape((8, 8))
    d = da.from_array(x, chunks=(4, 4))
    g = ghost(d, depth={0: 2, 1: 1}, boundary={0: 100, 1: 'reflect'})
    assert g.chunks == ((8, 8), (6, 6))
    expected = np.array(
      [[100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
       [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
       [  0,   0,   1,   2,   3,   4,   3,   4,   5,   6,   7,   7],
       [  8,   8,   9,  10,  11,  12,  11,  12,  13,  14,  15,  15],
       [ 16,  16,  17,  18,  19,  20,  19,  20,  21,  22,  23,  23],
       [ 24,  24,  25,  26,  27,  28,  27,  28,  29,  30,  31,  31],
       [ 32,  32,  33,  34,  35,  36,  35,  36,  37,  38,  39,  39],
       [ 40,  40,  41,  42,  43,  44,  43,  44,  45,  46,  47,  47],
       [ 16,  16,  17,  18,  19,  20,  19,  20,  21,  22,  23,  23],
       [ 24,  24,  25,  26,  27,  28,  27,  28,  29,  30,  31,  31],
       [ 32,  32,  33,  34,  35,  36,  35,  36,  37,  38,  39,  39],
       [ 40,  40,  41,  42,  43,  44,  43,  44,  45,  46,  47,  47],
       [ 48,  48,  49,  50,  51,  52,  51,  52,  53,  54,  55,  55],
       [ 56,  56,  57,  58,  59,  60,  59,  60,  61,  62,  63,  63],
       [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
       [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]])
    assert eq(g, expected)

    g = ghost(d, depth={0: 2, 1: 1}, boundary={0: 100})
    assert g.chunks == ((8, 8), (5, 5))

def test_map_overlap():
    x = da.arange(10, chunks=5)

    y = x.map_overlap(lambda x: x + len(x), depth=2)
    assert eq(y, np.arange(10) + 5 + 2 + 2)

def test_nearest_ghost():
    a = np.arange(144).reshape(12, 12).astype(float)

    darr = da.from_array(a, chunks=(6, 6))
    garr = ghost(darr, depth={0: 5, 1: 5},
                 boundary={0: 'nearest', 1: 'nearest'})
    tarr = trim_internal(garr, {0: 5, 1: 5})
    assert_array_almost_equal(tarr, a)

def test_0_depth():
    expected = np.arange(100).reshape(10, 10)
    darr = da.from_array(expected, chunks=(5, 2))

    depth = {0: 0, 1: 0}

    reflected = ghost(darr, depth=depth, boundary='reflect')
    nearest = ghost(darr, depth=depth, boundary='nearest')
    periodic = ghost(darr, depth=depth, boundary='periodic')
    constant = ghost(darr, depth=depth, boundary=42)

    result = trim_internal(reflected, depth)
    assert_array_equal(result, expected)

    result = trim_internal(nearest, depth)
    assert_array_equal(result, expected)

    result = trim_internal(periodic, depth)
    assert_array_equal(result, expected)

    result = trim_internal(constant, depth)
    assert_array_equal(result, expected)

def test_some_0_depth():
    set_trace()
    expected = np.arange(100).reshape(10, 10)
    darr = da.from_array(expected, chunks=(5, 2))

    depth = {0: 3, 1: 0}

    reflected = ghost(darr, depth=depth, boundary='reflect')
    nearest = ghost(darr, depth=depth, boundary='nearest')
    periodic = ghost(darr, depth=depth, boundary='periodic')
    constant = ghost(darr, depth=depth, boundary=42)

    result = trim_internal(reflected, depth)
    assert eq(result, expected)

    result = trim_internal(nearest, depth)
    assert_array_equal(result, expected)

    result = trim_internal(periodic, depth)
    assert_array_equal(result, expected)

    result = trim_internal(constant, depth)
    assert_array_equal(result, expected)

def test_depth_equals_boundary_length():
    expected = np.arange(100).reshape(10, 10)
    darr = da.from_array(expected, chunks=(5, 5))

    depth = {0: 5, 1: 5}

    reflected = ghost(darr, depth=depth, boundary='reflect')
    nearest = ghost(darr, depth=depth, boundary='nearest')
    periodic = ghost(darr, depth=depth, boundary='periodic')
    constant = ghost(darr, depth=depth, boundary=42)

    result = trim_internal(reflected, depth)
    assert_array_equal(result, expected)

    result = trim_internal(nearest, depth)
    assert_array_equal(result, expected)

    result = trim_internal(periodic, depth)
    assert_array_equal(result, expected)

    result = trim_internal(constant, depth)
    assert_array_equal(result, expected)

@pytest.mark.xfail
def test_depth_greater_than_boundary_length():
    expected = np.arange(100).reshape(10, 10)
    darr = da.from_array(expected, chunks=(5, 5))

    depth = {0: 8, 1: 7}

    reflected = ghost(darr, depth=depth, boundary='reflect')
    nearest = ghost(darr, depth=depth, boundary='nearest')
    periodic = ghost(darr, depth=depth, boundary='periodic')
    constant = ghost(darr, depth=depth, boundary=42)

    result = trim_internal(reflected, depth)
    assert_array_equal(result, expected)

    result = trim_internal(nearest, depth)
    assert_array_equal(result, expected)

    result = trim_internal(periodic, depth)
    assert_array_equal(result, expected)

    result = trim_internal(constant, depth)
    assert_array_equal(result, expected)
<|endoftext|>


<commit_before>#!/usr/bin/env python
import asyncio
import logging
import os

from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.orm.exc import NoResultFound

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtWidgets import QMessageBox

from osfoffline.application.background import BackgroundWorker
from osfoffline.database_manager.db import session
from osfoffline.database_manager.models import User
from osfoffline.database_manager.utils import save
from osfoffline.exceptions import AuthError
from osfoffline.utils.authentication import AuthClient
from osfoffline.utils.validators import validate_containing_folder
from osfoffline.views.preferences import Preferences
from osfoffline.views.start_screen import StartScreen
from osfoffline.views.system_tray import SystemTray
import osfoffline.alerts as AlertHandler

# RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"

logger = logging.getLogger(__name__)

class OSFApp(QDialog):
    login_signal = pyqtSignal()
    start_tray_signal = pyqtSignal()
    containing_folder_updated_signal = pyqtSignal()

    def __init__(self):
        super().__init__()

        # settings

        self.app_name = "OSFOffline"
        self.app_author = "COS"

        # views
        self.start_screen = StartScreen()
        self.tray = SystemTray()
        self.preferences = Preferences()
        AlertHandler.setup_alerts(self.tray.tray_icon, self.tray.tray_alert_signal)

        # connect all signal-slot pairs
        self.setup_connections()
        self.background_worker = BackgroundWorker()

    def setup_connections(self):
        # [ (signal, slot) ]
        signal_slot_pairs = [

            # system tray
            (self.tray.open_osf_folder_action.triggered, self.tray.open_osf_folder),
            (self.tray.launch_osf_action.triggered, self.tray.start_osf),
            # (self.tray.currently_synching_action.triggered, self.controller.currently_synching),
            (self.tray.preferences_action.triggered, self.open_preferences),
            (self.tray.about_action.triggered, self.start_about_screen),

            (self.tray.quit_action.triggered, self.quit),
            (self.tray.tray_alert_signal, self.tray.update_currently_synching),

            # main events
            (self.login_signal, self.start_screen.open_window),
            (self.start_tray_signal, self.tray.start),

            # preferences
            (self.preferences.preferences_window.desktopNotifications.stateChanged, self.preferences.alerts_changed),
            (self.preferences.preferences_window.startOnStartup.stateChanged, self.preferences.startup_changed),
            (self.preferences.preferences_window.changeFolderButton.clicked, self.preferences.set_containing_folder),
            (self.preferences.preferences_closed_signal, self.resume),
            (self.preferences.preferences_window.accountLogOutButton.clicked, self.logout),
            (self.preferences.containing_folder_updated_signal, self.tray.set_containing_folder),
            # (self.preferences.containing_folder_updated_signal, self.preferences.update_containing_folder_text_box),

            # start screen
            (self.start_screen.done_logging_in_signal, self.start),
            (self.start_screen.quit_application_signal, self.quit),

        ]
        for signal, slot in signal_slot_pairs:
            signal.connect(slot)

    def _can_restart_background_worker(self):
        try:
            user = self.get_current_user()
        except:
            return False
        if not user.logged_in:
            return False
        if not os.path.isdir(user.osf_local_folder_path):
            return False
        if not self.background_worker:
            return False
        if self.background_worker.is_alive():
            return False

        return True

    def start(self):
        logger.debug('Start in main called.')

        try:
            user = session.query(User).filter(User.logged_in).one()
        except MultipleResultsFound:
            session.query(User).delete()
            self.login_signal.emit()
            return
        except NoResultFound:
            self.login_signal.emit()
            return

        try:
            # Simple request to ensure user logged in with valid oauth_token
            user = asyncio.get_event_loop().run_until_complete(AuthClient().populate_user_data(user))
        except AuthError as e:
            logging.exception(e.message)
            self.login_signal.emit()

        containing_folder = os.path.dirname(user.osf_local_folder_path)
        while not validate_containing_folder(containing_folder):
            logger.warning('Invalid containing folder: {}'.format(containing_folder))
            AlertHandler.warn('Invalid containing folder. Please choose another.')
            containing_folder = os.path.abspath(self.set_containing_folder_initial())

        user.osf_local_folder_path = os.path.join(containing_folder, 'OSF')

        save(session, user)
        self.tray.set_containing_folder(containing_folder)

        if not os.path.isdir(user.osf_local_folder_path):
            os.makedirs(user.osf_local_folder_path)

        self.start_tray_signal.emit()
        logger.debug('starting background worker from main.start')

        self.background_worker = BackgroundWorker()
        self.background_worker.start()

    def resume(self):
        logger.debug('resuming')
        if self.background_worker.is_alive():
            raise RuntimeError('Resume called without first calling pause')

        self.background_worker = BackgroundWorker()
        self.background_worker.start()

    def pause(self):
        logger.debug('pausing')
        if self.background_worker and self.background_worker.is_alive():
            self.background_worker.stop()

    def quit(self):
        try:
            if self.background_worker.is_alive():
                logger.info('Stopping background worker')
                self.background_worker.stop()

            try:
                user = session.query(User).filter(User.logged_in).one()
            except NoResultFound:
                pass
            else:
                logger.info('Saving user data')
                save(session, user)
            session.close()
        finally:
            logger.info('Quitting application')
            QApplication.instance().quit()

    def get_current_user(self):
        return session.query(User).one()

    def set_containing_folder_initial(self):
        return QFileDialog.getExistingDirectory(self, "Choose where to place OSF folder")

    def logout(self):
        user = session.query(User).filter(User.logged_in).one()
        user.logged_in = False
        try:
            save(session, user)
        except SQLAlchemyError:
            session.query(User).delete()

        if self.preferences.isVisible():
            self.preferences.close()

        self.start_screen.open_window()

    def open_preferences(self):
        try:
            user = session.query(User).filter(User.logged_in).one()
        except:
            QMessageBox.warning(
                None,
                'Log in',
                'You must log in to view your preferences.')
            self.start_screen.show()
        else:
            logger.debug('pausing for preference modification')
            self.pause()
            logger.debug('opening preferences')
            self.preferences.open_window(Preferences.GENERAL)

    def start_about_screen(self):
        self.pause()
        self.preferences.open_window(Preferences.ABOUT)
<commit_msg>Ensure user is logged in before viewing settings<commit_after>#!/usr/bin/env python
import asyncio
import logging
import os

from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.orm.exc import NoResultFound

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtWidgets import QMessageBox

from osfoffline.application.background import BackgroundWorker
from osfoffline.database_manager.db import session
from osfoffline.database_manager.models import User
from osfoffline.database_manager.utils import save
from osfoffline.exceptions import AuthError
from osfoffline.utils.authentication import AuthClient
from osfoffline.utils.validators import validate_containing_folder
from osfoffline.views.preferences import Preferences
from osfoffline.views.start_screen import StartScreen
from osfoffline.views.system_tray import SystemTray
import osfoffline.alerts as AlertHandler

# RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"

logger = logging.getLogger(__name__)

class OSFApp(QDialog):
    login_signal = pyqtSignal()
    start_tray_signal = pyqtSignal()
    containing_folder_updated_signal = pyqtSignal()

    def __init__(self):
        super().__init__()

        # settings

        self.app_name = "OSFOffline"
        self.app_author = "COS"

        # views
        self.start_screen = StartScreen()
        self.tray = SystemTray()
        self.preferences = Preferences()
        AlertHandler.setup_alerts(self.tray.tray_icon, self.tray.tray_alert_signal)

        # connect all signal-slot pairs
        self.setup_connections()
        self.background_worker = BackgroundWorker()

    def setup_connections(self):
        # [ (signal, slot) ]
        signal_slot_pairs = [

            # system tray
            (self.tray.open_osf_folder_action.triggered, self.tray.open_osf_folder),
            (self.tray.launch_osf_action.triggered, self.tray.start_osf),
            # (self.tray.currently_synching_action.triggered, self.controller.currently_synching),
            (self.tray.preferences_action.triggered, self.open_preferences),
            (self.tray.about_action.triggered, self.start_about_screen),

            (self.tray.quit_action.triggered, self.quit),
            (self.tray.tray_alert_signal, self.tray.update_currently_synching),

            # main events
            (self.login_signal, self.start_screen.open_window),
            (self.start_tray_signal, self.tray.start),

            # preferences
            (self.preferences.preferences_window.desktopNotifications.stateChanged, self.preferences.alerts_changed),
            (self.preferences.preferences_window.startOnStartup.stateChanged, self.preferences.startup_changed),
            (self.preferences.preferences_window.changeFolderButton.clicked, self.preferences.set_containing_folder),
            (self.preferences.preferences_closed_signal, self.resume),
            (self.preferences.preferences_window.accountLogOutButton.clicked, self.logout),
            (self.preferences.containing_folder_updated_signal, self.tray.set_containing_folder),
            # (self.preferences.containing_folder_updated_signal, self.preferences.update_containing_folder_text_box),

            # start screen
            (self.start_screen.done_logging_in_signal, self.start),
            (self.start_screen.quit_application_signal, self.quit),

        ]
        for signal, slot in signal_slot_pairs:
            signal.connect(slot)

    def _can_restart_background_worker(self):
        try:
            user = self.get_current_user()
        except:
            return False
        if not user.logged_in:
            return False
        if not os.path.isdir(user.osf_local_folder_path):
            return False
        if not self.background_worker:
            return False
        if self.background_worker.is_alive():
            return False

        return True

    def start(self):
        logger.debug('Start in main called.')

        try:
            user = session.query(User).filter(User.logged_in).one()
        except MultipleResultsFound:
            session.query(User).delete()
            self.login_signal.emit()
            return
        except NoResultFound:
            self.login_signal.emit()
            return

        try:
            # Simple request to ensure user logged in with valid oauth_token
            user = asyncio.get_event_loop().run_until_complete(AuthClient().populate_user_data(user))
        except AuthError as e:
            logging.exception(e.message)
            self.login_signal.emit()

        containing_folder = os.path.dirname(user.osf_local_folder_path)
        while not validate_containing_folder(containing_folder):
            logger.warning('Invalid containing folder: {}'.format(containing_folder))
            AlertHandler.warn('Invalid containing folder. Please choose another.')
            containing_folder = os.path.abspath(self.set_containing_folder_initial())

        user.osf_local_folder_path = os.path.join(containing_folder, 'OSF')

        save(session, user)
        self.tray.set_containing_folder(containing_folder)

        if not os.path.isdir(user.osf_local_folder_path):
            os.makedirs(user.osf_local_folder_path)

        self.start_tray_signal.emit()
        logger.debug('starting background worker from main.start')

        self.background_worker = BackgroundWorker()
        self.background_worker.start()

    def resume(self):
        logger.debug('resuming')
        if self.background_worker.is_alive():
            raise RuntimeError('Resume called without first calling pause')

        self.background_worker = BackgroundWorker()
        self.background_worker.start()

    def pause(self):
        logger.debug('pausing')
        if self.background_worker and self.background_worker.is_alive():
            self.background_worker.stop()

    def quit(self):
        try:
            if self.background_worker.is_alive():
                logger.info('Stopping background worker')
                self.background_worker.stop()

            try:
                user = session.query(User).filter(User.logged_in).one()
            except NoResultFound:
                pass
            else:
                logger.info('Saving user data')
                save(session, user)
            session.close()
        finally:
            logger.info('Quitting application')
            QApplication.instance().quit()

    def get_current_user(self):
        return session.query(User).one()

    def set_containing_folder_initial(self):
        return QFileDialog.getExistingDirectory(self, "Choose where to place OSF folder")

    def logout(self):
        user = session.query(User).filter(User.logged_in).one()
        user.logged_in = False
        try:
            save(session, user)
        except SQLAlchemyError:
            session.query(User).delete()

        if self.preferences.isVisible():
            self.preferences.close()

        self.start_screen.open_window()

    def open_preferences(self):
        try:
            user = session.query(User).filter(User.logged_in).one()
        except:
            QMessageBox.warning(
                None,
                'Log in',
                'You must log in to view your preferences.')
            self.start_screen.show()
        else:
            logger.debug('pausing for preference modification')
            self.pause()
            logger.debug('opening preferences')
            self.preferences.open_window(Preferences.GENERAL)

    def start_about_screen(self):
        try:
            user = session.query(User).filter(User.logged_in).one()
        except:
            QMessageBox.warning(
                None,
                'Log in',
                'You must log in to view your preferences.')
            self.start_screen.show()
        else:
            self.pause()
            self.preferences.open_window(Preferences.ABOUT)
<|endoftext|>