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

import sys

from .utils import prepare_raise, construct_exc_class

# noinspection PyUnusedLocal
@prepare_raise
def raise_(type_, value=None, traceback=None):  # pylint: disable=W0613
    """
    Does the same as ordinary ``raise`` with arguments do in Python 2.
    But works in Python 3 (>= 3.3) also!

    Please checkout README on https://github.com/9seconds/pep3134
    to get an idea about possible pitfals. But short story is: please
    be pretty carefull with tracebacks. If it is possible, use sys.exc_info
    instead. But in most cases it will work as you expect.
    """

    prev_exc, prev_tb = sys.exc_info()[1:]
    proxy_class = construct_exc_class(type(type_))

    err = proxy_class(type_)
    err.__cause__ = None
    err.__suppress_context__ = False

    if getattr(prev_exc, "__pep3134__", False):
        prev_exc = prev_exc.with_traceback(prev_tb)
    err.__context__ = prev_exc

    if traceback:
        raise err.with_traceback(traceback), None, traceback
    else:
        raise err

def raise_from(exc, cause):
    """
    Does the same as ``raise LALALA from BLABLABLA`` does in Python 3.
    But works in Python 2 also!

    Please checkout README on https://github.com/9seconds/pep3134
    to get an idea about possible pitfals. But short story is: please
    be pretty carefull with tracebacks. If it is possible, use sys.exc_info
    instead. But in most cases it will work as you expect.
    """

    context, context_tb = sys.exc_info()[1:]

    incorrect_cause = not (
        (isinstance(cause, type) and issubclass(cause, Exception)) or
        isinstance(cause, BaseException) or
        cause is None
    )
    if incorrect_cause:
        raise TypeError("exception causes must derive from BaseException")

    if cause is not None:
        if not getattr(cause, "__pep3134__", False):
            # noinspection PyBroadException
            try:
                raise_(cause)
            except:  # noqa pylint: disable=W0702
                cause = sys.exc_info()[1]
        cause.__fixed_traceback__ = context_tb

    # noinspection PyBroadException
    try:
        raise_(exc)
    except:  # noqa pylint: disable=W0702
        exc = sys.exc_info()[1]

    exc.__suppress_context__ = True
    exc.__cause__ = cause
    exc.__context__ = None

    raise exc
<commit_msg>Fix for small lint problem<commit_after># -*- coding: utf-8 -*-

import sys

from .utils import prepare_raise, construct_exc_class

# noinspection PyUnusedLocal
@prepare_raise
def raise_(type_, value=None, traceback=None):  # pylint: disable=W0613
    """
    Does the same as ordinary ``raise`` with arguments do in Python 2.
    But works in Python 3 (>= 3.3) also!

    Please checkout README on https://github.com/9seconds/pep3134
    to get an idea about possible pitfals. But short story is: please
    be pretty carefull with tracebacks. If it is possible, use sys.exc_info
    instead. But in most cases it will work as you expect.
    """

    prev_exc, prev_tb = sys.exc_info()[1:]
    proxy_class = construct_exc_class(type(type_))

    err = proxy_class(type_)
    err.__cause__ = None
    err.__suppress_context__ = False

    if getattr(prev_exc, "__pep3134__", False):
        prev_exc = prev_exc.with_traceback(prev_tb)
    err.__context__ = prev_exc

    if traceback:
        raise err.with_traceback(traceback), None, traceback
    else:
        raise err

def raise_from(exc, cause):
    """
    Does the same as ``raise LALALA from BLABLABLA`` does in Python 3.
    But works in Python 2 also!

    Please checkout README on https://github.com/9seconds/pep3134
    to get an idea about possible pitfals. But short story is: please
    be pretty carefull with tracebacks. If it is possible, use sys.exc_info
    instead. But in most cases it will work as you expect.
    """

    context_tb = sys.exc_info()[2]

    incorrect_cause = not (
        (isinstance(cause, type) and issubclass(cause, Exception)) or
        isinstance(cause, BaseException) or
        cause is None
    )
    if incorrect_cause:
        raise TypeError("exception causes must derive from BaseException")

    if cause is not None:
        if not getattr(cause, "__pep3134__", False):
            # noinspection PyBroadException
            try:
                raise_(cause)
            except:  # noqa pylint: disable=W0702
                cause = sys.exc_info()[1]
        cause.__fixed_traceback__ = context_tb

    # noinspection PyBroadException
    try:
        raise_(exc)
    except:  # noqa pylint: disable=W0702
        exc = sys.exc_info()[1]

    exc.__suppress_context__ = True
    exc.__cause__ = cause
    exc.__context__ = None

    raise exc
<|endoftext|>


<commit_before>"""
Comments:
If you start from featured globals it seems that slab etc is off enough where
particles get added in regions they shouldn't be (e.g. below the slab).
So maybe you do a polish or a burn before an addsubtract?
"""
import os
import Tkinter as tk
import tkFileDialog as tkfd
import numpy as np
import peri
from peri import initializers, util, models, states, logger
from peri.comp import ilms, objs, psfs, exactpsf, comp

RLOG = logger.log.getChild('runner')

import peri.opt.optimize as opt
import peri.opt.addsubtract as addsub

def locate_spheres(image, radius, dofilter=True, order=(7,7,7), invert=False):
    """
    Get an initial featuring of sphere positions in an image.

    Parameters:
    -----------
    image : `peri.util.Image` object
        Image object which defines the image file as well as the region.

    radius : float
        Radius of objects to find, in pixels

    dofilter : boolean
        Whether to remove the background before featuring. Doing so can often
        greatly increase the success of initial featuring and decrease later
        optimization time.

    zslab : float
        Location of the coverslip in z pixel distance.

    invert : boolean
        Whether to invert the image for featuring. Should be True is the image
        is bright particles on a dark background.

    Returns:
    --------
    positions : np.ndarray [N,3]
        Positions of the particles in order (z,y,x) in pixel units of the image.
    """
    # We just want a smoothed field model of the image so that the residuals
    # are simply the particles without other complications
    m = models.SmoothFieldModel()

    I = ilms.LegendrePoly2P1D(order=order, constval=image.get_image().mean())
    s = states.ImageState(image, [I], pad=0, mdl=m)

    if dofilter:
        opt.do_levmarq(s, s.params)

    return addsub.feature_guess(s, radius, invert=not invert)[0]

def get_initial_featuring(feature_diam, actual_rad=None, im_name=None, desc='',
        tile=None, invert=True, minmass=100.0, slab=None, min_rad=None,
         max_rad=None, max_mem=1e9, zscale=0.9, use_aug=False):
    """
    Gets a completely-optimized state from an initial image of single-sized
    particles. The user interactively selects the image.

    Parameters
    ----------
        feature_diam : Int, odd
            The particle diameter for featuring, as passed to trackpy.locate
        actual_rad : Float
            The actual radius of the particles. Default is 0.5 * feature_diam

        desc : String
            A description to be inserted in saved state. The save name will
            be, e.g., '0.tif-peri-' + desc + 'initial-burn.pkl'. Default is ''
        tile : peri.util.Tile instance
            The tile of the raw image to be analyzed. Default is None, the
            entire image.

        invert : Bool
            Whether to invert the image for featuring, as passed to trackpy.
            Default is True.
        minmass : Float
            minmass for featuring, as passed to trackpy. Default is 100.

        slab : peri.comp.objs.Slab instance or None
            If not None, a slab corresponding to that in the image. Default
            is None.

        min_rad : Float
            The minimum particle radius, as passed to addsubtract.add_subtract.
            Particles with a fitted radius smaller than this are identified
            as fake and removed. Default is 0.5 * actual_rad.
        max_rad : Float
            The maximum particle radius, as passed to addsubtract.add_subtract.
            Particles with a fitted radius larger than this are identified
            as fake and removed. Default is 1.5 * actual_rad, however you
            may find better results if you make this more stringent.

        max_mem : Numeric
            The maximum additional memory to use for the optimizers, as
            passed to optimize.burn. Default is 1e9.
    """
    if actual_rad is None:
        actual_rad = feature_diam * 0.5
    if min_rad is None:
        min_rad = 0.5 * actual_rad
    if max_rad is None:
        max_rad = 1.5 * actual_rad

    _,  im_name = _pick_state_im_name('', im_name, use_full_path=use_full_path)
    im = util.RawImage(im_name, tile=tile)

    f = peri.trackpy.locate(im.get_image()*255, feature_diam, invert=invert,
            minmass=minmass)
    npart = f['x'].size
    pos = np.zeros([npart,3])
    pos[:,0] = f['z']
    pos[:,1] = f['y']
    pos[:,2] = f['x']

    rad = np.ones(npart, dtype='float') * actual_rad
    s = _optimize_from_centroid(pos, rad, im, slab, max_mem=max_mem, desc=desc)
    #FIXME kwargs
    return s

def feature_from_pos_rad(pos, rad, im_name, desc='', tile=None, invert=True,
        minmass=100.0, slab=None, min_rad=None, max_rad=None, max_mem=1e9,
        zscale=0.9, use_aug=False):
    im = util.RawImage(im_name, tile=tile)
    s = _optimize_from_centroid(pos, rad, im, slab, max_mem=max_mem, desc=desc)
    return s

def _optimize_from_centroid(pos, rad, im, slab, max_mem=1e9, desc='',
        min_rad=None, max_rad=None, invert=None, use_aug=False):
    if slab is not None:
        o = comp.ComponentCollection(
                [
                    objs.PlatonicSpheresCollection(pos, rad, zscale=zscale),
                    slab
                ],
                category='obj'
            )
    else:
        o = objs.PlatonicSpheresCollection(pos, rad, zscale=zscale)

    p = exactpsf.FixedSSChebLinePSF()
    i = ilms.BarnesStreakLegPoly2P1D(npts=(200,120,80,50,30,30,30,30,30,30,30),
            zorder=9) #FIXME npts needs to be based on image size
    b = ilms.LegendrePoly2P1D(order=(9,3,5), category='bkg') #FIXME order needs to be based on image size, slab
    c = comp.GlobalScalar('offset', 0.0)
    s = states.ImageState(im, [o, i, b, c, p])
    RLOG.info('State Created.')

    opt.do_levmarq(s, ['ilm-scale'], max_iter=1, run_length=6, max_mem=max_mem)
    states.save(s, desc=desc+'-initial')

    RLOG.info('Initial burn:')
    opt.burn(s, mode='burn', n_loop=4, ftol=1, desc=desc+'initial-burn',
            max_mem=max_mem)

    RLOG.info('Start add-subtract')
    addsub.add_subtract(s, tries=30, min_rad=min_rad, max_rad=max_rad,
            invert=invert)
    states.save(s, desc=desc+'initial-addsub')

    RLOG.info('Final polish:')
    opt.burn(s, mode='polish', n_loop=7, ftol=1e-3, desc=desc+'addsub-polish',
            max_mem=max_mem, use_aug=use_aug)

    # os.chdir(initial_dir) ???
    return s

def translate_featuring(state_name=None, im_name=None, desc='', invert=True,
        min_rad='calc', max_rad='calc', max_mem=1e9, do_polish=True,
        use_full_path=False):
    """
    Translates one optimized state into another image where the particles
    have moved by a small amount (~1 particle radius).
    Returns a completely-optimized state. The user can interactively selects
    the initial state and the second raw image.

    Parameters
    ----------
        desc : String
            A description to be inserted in saved state. The save name will
            be, e.g., '0.tif-peri-' + desc + 'initial-burn.pkl'. Default is ''

        invert : Bool
            Whether to invert the image for featuring, as passed to
            addsubtract.add_subtract. Default is True.
        min_rad : Float
            The minimum particle radius, as passed to addsubtract.add_subtract.
            Default is 'calc', but a known physical value will give better
            answers.
        max_rad : Float
            The maximum particle radius, as passed to addsubtract.add_subtract.
            Default is 'calc', but a known physical value will give better
            answers.

        max_mem : Numeric
            The maximum additional memory to use for the optimizers, as
            passed to optimize.burn. Default is 1e9.
    """
    state_name, im_name = _pick_state_im_name(state_name, im_name,
                use_full_path=use_full_path)

    s = states.load(state_name)
    im = util.RawImage(im_name, tile=s.image.tile)  #should have get_scale? FIXME

    s.set_image(im)
    _translate_particles(s, desc, max_mem, min_rad, max_rad, invert,
            do_polish=do_polish)
    return s

def get_particles_featuring(feature_diam, state_name=None, im_name=None,
        actual_rad=None, desc='', invert=True, min_rad='calc', max_rad='calc',
         max_mem=1e9, zscale=0.9, minmass=100, use_full_path=False):
    """
    Runs trackpy.locate on an image, sets the globals from a previous state,
    calls _translate_particles

    Basically I'm trying to cover 4 options, one of each:
        (Previously featured state,     No previously featured state)
        (using previous positions,      no previous positions)
    (no, no)    = get_initial_featuring
    (yes, no)   = get_particle_featuring
    (yes, yes)  = translate_featuring
    (no, yes)   = stupid, not doing. Or should I???

    These do:
        (use globals to start,          start from nothing)
        (use positions to start,        start from trackpy)
    """
    state_name, im_name = _pick_state_im_name(state_name, im_name,
            use_full_path=use_full_path)
    s = states.load(state_name)

    if actual_rad == None:
        actual_rad = np.median(s.obj_get_radii())  #or 2 x feature_diam?
    im = util.RawImage(im_name, tile=s.image.tile)  #should have get_scale? FIXME
    f = peri.trackpy.locate(im.get_image()*255, feature_diam, invert=invert,
            minmass=minmass)
    npart = f['x'].size
    pos = np.zeros([npart,3])
    pos[:,0] = f['z']
    pos[:,1] = f['y']
    pos[:,2] = f['x']
    #Right now there is not a good way to translate, so:

    slab = s.get('obj').comps[1] #FIXME I don't think this will always be correct
    sph = objs.PlatonicSpheresCollection(pos=pos, rad=actual_rad, zscale=
            s.state['zscale'])
    o = comp.ComponentCollection([sph, slab], category='obj')
    s.set('obj', o)

    s.set_image(im)
    _translate_particles(s, desc, max_mem, min_rad, max_rad, invert,
        do_polish=True)
    return s

def _pick_state_im_name(state_name, im_name, use_full_path=False):
    initial_dir = os.getcwd()
    if (state_name is None) or (im_name is None):
        wid = tk.Tk()
        wid.withdraw()
    if state_name is None:
        state_name = tkfd.askopenfilename(initialdir=initial_dir, title=
                'Select pre-featured state')
        os.chdir(os.path.dirname(state_name))

    if im_name is None:
        im_name = tkfd.askopenfilename(initialdir=initial_dir, title=
                'Select new image')

    if not use_full_path:
        im_path = os.path.dirname(im_name)
        os.chdir(im_path)
        im_name = os.path.basename(im_name)
    else:
        os.chdir(initial_dir)
    return state_name, im_name

def _translate_particles(s, desc, max_mem, min_rad, max_rad, invert,
        do_polish=True):
    RLOG.info('Translate Particles:')
    opt.burn(s, mode='do-particles', n_loop=2, ftol=1, desc=desc+
            'translate-particles', max_mem=max_mem, include_rad=False)
    opt.burn(s, mode='do-particles', n_loop=2, ftol=1, desc=desc+
            'translate-particles', max_mem=max_mem, include_rad=True)

    RLOG.info('Start add-subtract')
    addsub.add_subtract(s, tries=30, min_rad=min_rad, max_rad=max_rad,
        invert=invert)
    states.save(s, desc=desc+'translate-addsub')

    if do_polish:
        RLOG.info('Final polish:')
        opt.burn(s, mode='polish', n_loop=6, ftol=1e-3, desc=desc+
            'addsub-polish', max_mem=max_mem)
<commit_msg>runner.feature_from_pos_rad should be working.<commit_after>"""
Comments:
If you start from featured globals it seems that slab etc is off enough where
particles get added in regions they shouldn't be (e.g. below the slab).
So maybe you do a polish or a burn before an addsubtract?
"""
import os
import Tkinter as tk
import tkFileDialog as tkfd
import numpy as np
import peri
from peri import initializers, util, models, states, logger
from peri.comp import ilms, objs, psfs, exactpsf, comp

RLOG = logger.log.getChild('runner')

import peri.opt.optimize as opt
import peri.opt.addsubtract as addsub

def locate_spheres(image, radius, dofilter=True, order=(7,7,7), invert=False):
    """
    Get an initial featuring of sphere positions in an image.

    Parameters:
    -----------
    image : `peri.util.Image` object
        Image object which defines the image file as well as the region.

    radius : float
        Radius of objects to find, in pixels

    dofilter : boolean
        Whether to remove the background before featuring. Doing so can often
        greatly increase the success of initial featuring and decrease later
        optimization time.

    zslab : float
        Location of the coverslip in z pixel distance.

    invert : boolean
        Whether to invert the image for featuring. Should be True is the image
        is bright particles on a dark background.

    Returns:
    --------
    positions : np.ndarray [N,3]
        Positions of the particles in order (z,y,x) in pixel units of the image.
    """
    # We just want a smoothed field model of the image so that the residuals
    # are simply the particles without other complications
    m = models.SmoothFieldModel()

    I = ilms.LegendrePoly2P1D(order=order, constval=image.get_image().mean())
    s = states.ImageState(image, [I], pad=0, mdl=m)

    if dofilter:
        opt.do_levmarq(s, s.params)

    return addsub.feature_guess(s, radius, invert=not invert)[0]

def get_initial_featuring(feature_diam, actual_rad=None, im_name=None, desc='',
        tile=None, invert=True, minmass=100.0, slab=None, min_rad=None,
         max_rad=None, max_mem=1e9, zscale=0.9, use_aug=False):
    """
    Gets a completely-optimized state from an initial image of single-sized
    particles. The user interactively selects the image.

    Parameters
    ----------
        feature_diam : Int, odd
            The particle diameter for featuring, as passed to trackpy.locate
        actual_rad : Float
            The actual radius of the particles. Default is 0.5 * feature_diam

        desc : String
            A description to be inserted in saved state. The save name will
            be, e.g., '0.tif-peri-' + desc + 'initial-burn.pkl'. Default is ''
        tile : peri.util.Tile instance
            The tile of the raw image to be analyzed. Default is None, the
            entire image.

        invert : Bool
            Whether to invert the image for featuring, as passed to trackpy.
            Default is True.
        minmass : Float
            minmass for featuring, as passed to trackpy. Default is 100.

        slab : peri.comp.objs.Slab instance or None
            If not None, a slab corresponding to that in the image. Default
            is None.

        min_rad : Float
            The minimum particle radius, as passed to addsubtract.add_subtract.
            Particles with a fitted radius smaller than this are identified
            as fake and removed. Default is 0.5 * actual_rad.
        max_rad : Float
            The maximum particle radius, as passed to addsubtract.add_subtract.
            Particles with a fitted radius larger than this are identified
            as fake and removed. Default is 1.5 * actual_rad, however you
            may find better results if you make this more stringent.

        max_mem : Numeric
            The maximum additional memory to use for the optimizers, as
            passed to optimize.burn. Default is 1e9.
    """
    if actual_rad is None:
        actual_rad = feature_diam * 0.5

    _,  im_name = _pick_state_im_name('', im_name, use_full_path=use_full_path)
    im = util.RawImage(im_name, tile=tile)

    f = peri.trackpy.locate(im.get_image()*255, feature_diam, invert=invert,
            minmass=minmass)
    npart = f['x'].size
    pos = np.zeros([npart,3])
    pos[:,0] = f['z']
    pos[:,1] = f['y']
    pos[:,2] = f['x']

    rad = np.ones(npart, dtype='float') * actual_rad
    s = _optimize_from_centroid(pos, rad, im, invert=invert, **kwargs)
    #FIXME kwargs
    return s

def feature_from_pos_rad(pos, rad, im_name, tile=None, **kwargs):
    im = util.RawImage(im_name, tile=tile)
    s = _optimize_from_centroid(pos, rad, im, **kwargs)
    return s

def _optimize_from_centroid(pos, rad, im, slab=None, max_mem=1e9, desc='',
        min_rad=None, max_rad=None, invert=True, use_aug=False, zscale=1.0):
    if min_rad is None:
        min_rad = 0.5 * rad.mean()
    if max_rad is None:
        max_rad = 1.5 * rad.mean() #FIXME these could be problem for bidisperse suspensions
    if slab is not None:
        o = comp.ComponentCollection(
                [
                    objs.PlatonicSpheresCollection(pos, rad, zscale=zscale),
                    slab
                ],
                category='obj'
            )
    else:
        o = objs.PlatonicSpheresCollection(pos, rad, zscale=zscale)

    p = exactpsf.FixedSSChebLinePSF()
    i = ilms.BarnesStreakLegPoly2P1D(npts=(200,120,80,50,30,30,30,30,30,30,30),
            zorder=9) #FIXME npts needs to be based on image size
    b = ilms.LegendrePoly2P1D(order=(9,3,5), category='bkg') #FIXME order needs to be based on image size, slab
    c = comp.GlobalScalar('offset', 0.0)
    s = states.ImageState(im, [o, i, b, c, p])
    RLOG.info('State Created.')

    opt.do_levmarq(s, ['ilm-scale'], max_iter=1, run_length=6, max_mem=max_mem)
    states.save(s, desc=desc+'-initial')

    RLOG.info('Initial burn:')
    opt.burn(s, mode='burn', n_loop=4, ftol=1, desc=desc+'initial-burn',
            max_mem=max_mem)

    RLOG.info('Start add-subtract')
    addsub.add_subtract(s, tries=30, min_rad=min_rad, max_rad=max_rad,
            invert=invert)
    states.save(s, desc=desc+'initial-addsub')

    RLOG.info('Final polish:')
    opt.burn(s, mode='polish', n_loop=7, ftol=1e-3, desc=desc+'addsub-polish',
            max_mem=max_mem, use_aug=use_aug)

    # os.chdir(initial_dir) ???
    return s

def translate_featuring(state_name=None, im_name=None, desc='', invert=True,
        min_rad='calc', max_rad='calc', max_mem=1e9, do_polish=True,
        use_full_path=False):
    """
    Translates one optimized state into another image where the particles
    have moved by a small amount (~1 particle radius).
    Returns a completely-optimized state. The user can interactively selects
    the initial state and the second raw image.

    Parameters
    ----------
        desc : String
            A description to be inserted in saved state. The save name will
            be, e.g., '0.tif-peri-' + desc + 'initial-burn.pkl'. Default is ''

        invert : Bool
            Whether to invert the image for featuring, as passed to
            addsubtract.add_subtract. Default is True.
        min_rad : Float
            The minimum particle radius, as passed to addsubtract.add_subtract.
            Default is 'calc', but a known physical value will give better
            answers.
        max_rad : Float
            The maximum particle radius, as passed to addsubtract.add_subtract.
            Default is 'calc', but a known physical value will give better
            answers.

        max_mem : Numeric
            The maximum additional memory to use for the optimizers, as
            passed to optimize.burn. Default is 1e9.
    """
    state_name, im_name = _pick_state_im_name(state_name, im_name,
                use_full_path=use_full_path)

    s = states.load(state_name)
    im = util.RawImage(im_name, tile=s.image.tile)  #should have get_scale? FIXME

    s.set_image(im)
    _translate_particles(s, desc, max_mem, min_rad, max_rad, invert,
            do_polish=do_polish)
    return s

def get_particles_featuring(feature_diam, state_name=None, im_name=None,
        actual_rad=None, desc='', invert=True, min_rad='calc', max_rad='calc',
         max_mem=1e9, zscale=0.9, minmass=100, use_full_path=False):
    """
    Runs trackpy.locate on an image, sets the globals from a previous state,
    calls _translate_particles

    Basically I'm trying to cover 4 options, one of each:
        (Previously featured state,     No previously featured state)
        (using previous positions,      no previous positions)
    (no, no)    = get_initial_featuring
    (yes, no)   = get_particle_featuring
    (yes, yes)  = translate_featuring
    (no, yes)   = stupid, not doing. Or should I???

    These do:
        (use globals to start,          start from nothing)
        (use positions to start,        start from trackpy)
    """
    state_name, im_name = _pick_state_im_name(state_name, im_name,
            use_full_path=use_full_path)
    s = states.load(state_name)

    if actual_rad == None:
        actual_rad = np.median(s.obj_get_radii())  #or 2 x feature_diam?
    im = util.RawImage(im_name, tile=s.image.tile)  #should have get_scale? FIXME
    f = peri.trackpy.locate(im.get_image()*255, feature_diam, invert=invert,
            minmass=minmass)
    npart = f['x'].size
    pos = np.zeros([npart,3])
    pos[:,0] = f['z']
    pos[:,1] = f['y']
    pos[:,2] = f['x']
    #Right now there is not a good way to translate, so:

    slab = s.get('obj').comps[1] #FIXME I don't think this will always be correct
    sph = objs.PlatonicSpheresCollection(pos=pos, rad=actual_rad, zscale=
            s.state['zscale'])
    o = comp.ComponentCollection([sph, slab], category='obj')
    s.set('obj', o)

    s.set_image(im)
    _translate_particles(s, desc, max_mem, min_rad, max_rad, invert,
        do_polish=True)
    return s

def _pick_state_im_name(state_name, im_name, use_full_path=False):
    initial_dir = os.getcwd()
    if (state_name is None) or (im_name is None):
        wid = tk.Tk()
        wid.withdraw()
    if state_name is None:
        state_name = tkfd.askopenfilename(initialdir=initial_dir, title=
                'Select pre-featured state')
        os.chdir(os.path.dirname(state_name))

    if im_name is None:
        im_name = tkfd.askopenfilename(initialdir=initial_dir, title=
                'Select new image')

    if not use_full_path:
        im_path = os.path.dirname(im_name)
        os.chdir(im_path)
        im_name = os.path.basename(im_name)
    else:
        os.chdir(initial_dir)
    return state_name, im_name

def _translate_particles(s, desc, max_mem, min_rad, max_rad, invert,
        do_polish=True):
    RLOG.info('Translate Particles:')
    opt.burn(s, mode='do-particles', n_loop=2, ftol=1, desc=desc+
            'translate-particles', max_mem=max_mem, include_rad=False)
    opt.burn(s, mode='do-particles', n_loop=2, ftol=1, desc=desc+
            'translate-particles', max_mem=max_mem, include_rad=True)

    RLOG.info('Start add-subtract')
    addsub.add_subtract(s, tries=30, min_rad=min_rad, max_rad=max_rad,
        invert=invert)
    states.save(s, desc=desc+'translate-addsub')

    if do_polish:
        RLOG.info('Final polish:')
        opt.burn(s, mode='polish', n_loop=6, ftol=1e-3, desc=desc+
            'addsub-polish', max_mem=max_mem)
<|endoftext|>


<commit_before>from apis.resources.base import BaseResource
from models import Role, Person
from tastypie.constants import ALL, ALL_WITH_RELATIONS
import tastypie.fields as fields
from django.contrib.auth.models import User

class RoleResource(BaseResource):
    ''' Role API
    '''
    class Meta(BaseResource.Meta):
        queryset = Role.objects.all()
        allowed_methods = ['get']
        excludes = ["id"]
        include_resource_uri = False

class PersonResource(BaseResource):
    class Meta(BaseResource.Meta):
        queryset = Person.objects.all()
        allowed_methods = ['get']

    def get_object_list(self, request):
        persons = super(PersonResource, self).get_object_list(request)
        user_id = request.GET.get('user_id', '')
        if len(user_id) > 0:
            persons = persons.filter(user__id=user_id)
        return persons<commit_msg>Allow filtering Person API by role #307<commit_after>from apis.resources.base import BaseResource
from models import Role, Person
from tastypie.constants import ALL, ALL_WITH_RELATIONS
import tastypie.fields as fields
from django.contrib.auth.models import User

class RoleResource(BaseResource):
    ''' Role API
    '''
    class Meta(BaseResource.Meta):
        queryset = Role.objects.all()
        allowed_methods = ['get']
        excludes = ["id"]
        include_resource_uri = False
        filtering = {
                'org': ALL,
                'text': ALL,
                }

class PersonResource(BaseResource):

    roles = fields.ToManyField(RoleResource, 'roles', full=True)
    mk = fields.ToOneField('mks.api.MemberResource', 'mk', null=True, full=True)

    class Meta(BaseResource.Meta):
        queryset = Person.objects.all()
        allowed_methods = ['get']
        filtering = {
                'roles': ALL_WITH_RELATIONS,
                'roles__org': ALL,
                }

    def get_object_list(self, request):
        persons = super(PersonResource, self).get_object_list(request)
        user_id = request.GET.get('user_id', '')
        if len(user_id) > 0:
            persons = persons.filter(user__id=user_id)
        return persons
<|endoftext|>


<commit_before>import csv
import json
import logging
import re
from pextant.solvers.astarSEXTANT import fullSearch, ExplorerCost
from pextant.analysis.loadWaypoints import JSONloader
logger = logging.getLogger()

class Pathfinder:
    """
    This class performs the A* path finding algorithm and contains the Cost Functions. Also includes
    capabilities for analysis of a path.

    This class still needs performance testing for maps of larger sizes. I don't believe that
    we will be doing anything extremely computationally intensive though.

    Current cost functions are Time, Distance, and (Metabolic) Energy. It would be useful to be able to
    optimize on other resources like battery power or water sublimated, but those are significantly more
    difficult because they depend on shadowing and was not implemented by Aaron.
    """
    def __init__(self, explorer_model, environmental_model):
        self.explorer = explorer_model
        self.map = environmental_model

    def aStarCompletePath(self, optimize_on, waypoints, returnType="JSON", dh=None, fileName=None ):
        pass

    def completeSearch(self, optimize_on, waypoints, filepath=None ):
        """
        Returns a tuple representing the path and the total cost of the path.
        The path will be a list. All activity points will be duplicated in
        the returned path.

        waypoints is a list of activityPoint objects, in the correct order. fileName is
        used when we would like to write stuff to a file and is currently necessary
        for csv return types.
        """
        env_model = self.map
        explorer_model = self.explorer
        cost_function = ExplorerCost(explorer_model, env_model, optimize_on)
        segmentsout, rawpoints, items = fullSearch(waypoints, env_model, cost_function)

        extension = re.search('^(.+\/[^/]+)\.(\w+)$', filepath).group(2)

        if extension == "json":
            jsonout = []
            for segment in segmentsout:
                jsonout += [segment.tojson()]
            json.dump(jsonout.tojson(), filepath)
        elif extension == "csv":
            rows = [['isStation', 'x', 'y', 'z', 'distanceMeters', 'energyJoules', 'timeSeconds']]
            for segment in segmentsout:
                rows += segment.tocsv() #still need to fix that the same point is included twice
            with open(filepath, 'wb') as csvfile:
                writer = csv.writer(csvfile)
                for row in rows:
                    writer.writerow(row)
            return rows

    def completeSearchFromJSON(self, optimize_on, jsonInput, filepath=None, algorithm="A*",
                               numTestPoints=0):
        jloader = JSONloader(jsonInput)
        waypoints = jloader.get_waypoints()

        #if algorithm == "A*":
        segmentsout = self.completeSearch(optimize_on, waypoints, filepath)
        updatedjson = jloader.add_search_sol(segmentsout)

        return updatedjson

if __name__ == '__main__':
    from pextant.analysis.loadWaypoints import loadPoints
    from ExplorerModel import Astronaut
    from EnvironmentalModel import GDALMesh

    hi_low = GDALMesh('maps/HI_lowqual_DEM.tif')
    waypoints = loadPoints('waypoints/HI_13Nov16_MD7_A.json')
    env_model = hi_low.loadMapSection(waypoints.geoEnvelope())
    astronaut = Astronaut(80)
    pathfinder = Pathfinder(astronaut, env_model)
    out = pathfinder.aStarCompletePath('Energy', waypoints)
    print out<commit_msg>bugfix and some function call restrucuring<commit_after>import csv
import json
import logging
import re
from pextant.solvers.astarSEXTANT import fullSearch, ExplorerCost
from pextant.analysis.loadWaypoints import JSONloader
logger = logging.getLogger()

class Pathfinder:
    """
    This class performs the A* path finding algorithm and contains the Cost Functions. Also includes
    capabilities for analysis of a path.

    This class still needs performance testing for maps of larger sizes. I don't believe that
    we will be doing anything extremely computationally intensive though.

    Current cost functions are Time, Distance, and (Metabolic) Energy. It would be useful to be able to
    optimize on other resources like battery power or water sublimated, but those are significantly more
    difficult because they depend on shadowing and was not implemented by Aaron.
    """
    def __init__(self, explorer_model, environmental_model):
        self.explorer = explorer_model
        self.map = environmental_model

    def aStarCompletePath(self, optimize_on, waypoints, returnType="JSON", dh=None, fileName=None ):
        pass

    def completeSearch(self, optimize_on, waypoints, filepath=None ):
        """
        Returns a tuple representing the path and the total cost of the path.
        The path will be a list. All activity points will be duplicated in
        the returned path.

        waypoints is a list of activityPoint objects, in the correct order. fileName is
        used when we would like to write stuff to a file and is currently necessary
        for csv return types.
        """
        env_model = self.map
        explorer_model = self.explorer
        cost_function = ExplorerCost(explorer_model, env_model, optimize_on)
        segmentsout, rawpoints, items = fullSearch(waypoints, env_model, cost_function)

        if filepath:
            extension = re.search('^(.+\/[^/]+)\.(\w+)$', filepath).group(2)
        else:
            extension = None

        if extension == "json":
            jsonout = []
            for segment in segmentsout:
                jsonout += [segment.tojson()]
            json.dump(jsonout.tojson(), filepath)
        elif extension == "csv":
            rows = [['isStation', 'x', 'y', 'z', 'distanceMeters', 'energyJoules', 'timeSeconds']]
            for segment in segmentsout:
                rows += segment.tocsv() #still need to fix that the same point is included twice
            with open(filepath, 'wb') as csvfile:
                writer = csv.writer(csvfile)
                for row in rows:
                    writer.writerow(row)
            return rows
        return segmentsout, rawpoints, items

    def completeSearchFromJSON(self, optimize_on, jsonInput, filepath=None, algorithm="A*",
                               numTestPoints=0):
        jloader = JSONloader(jsonInput)
        waypoints = jloader.get_waypoints()

        #if algorithm == "A*":
        segmentsout,_,_ = self.completeSearch(optimize_on, waypoints, filepath)
        updatedjson = jloader.add_search_sol(segmentsout)

        return updatedjson

if __name__ == '__main__':
    from pextant.analysis.loadWaypoints import loadPoints
    from ExplorerModel import Astronaut
    from EnvironmentalModel import GDALMesh

    hi_low = GDALMesh('maps/HI_lowqual_DEM.tif')
    waypoints = loadPoints('waypoints/HI_13Nov16_MD7_A.json')
    env_model = hi_low.loadMapSection(waypoints.geoEnvelope())
    astronaut = Astronaut(80)
    pathfinder = Pathfinder(astronaut, env_model)
    out = pathfinder.aStarCompletePath('Energy', waypoints)
    print out<|endoftext|>


<commit_before>"""Support code for distutils test cases."""
import os
import sys
import shutil
import tempfile
import unittest
import sysconfig
from copy import deepcopy

from distutils import log
from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL
from distutils.core import Distribution

class LoggingSilencer(object):

    def setUp(self):
        super().setUp()
        self.threshold = log.set_threshold(log.FATAL)
        # catching warnings
        # when log will be replaced by logging
        # we won't need such monkey-patch anymore
        self._old_log = log.Log._log
        log.Log._log = self._log
        self.logs = []

    def tearDown(self):
        log.set_threshold(self.threshold)
        log.Log._log = self._old_log
        super().tearDown()

    def _log(self, level, msg, args):
        if level not in (DEBUG, INFO, WARN, ERROR, FATAL):
            raise ValueError('%s wrong log level' % str(level))
        if not isinstance(msg, str):
            raise TypeError("msg should be str, not '%.200s'"
                            % (type(msg).__name__))
        self.logs.append((level, msg, args))

    def get_logs(self, *levels):
        def _format(msg, args):
            return msg % args
        return [msg % args for level, msg, args
                in self.logs if level in levels]

    def clear_logs(self):
        self.logs = []

class TempdirManager(object):
    """Mix-in class that handles temporary directories for test cases.

    This is intended to be used with unittest.TestCase.
    """

    def setUp(self):
        super().setUp()
        self.old_cwd = os.getcwd()
        self.tempdirs = []

    def tearDown(self):
        # Restore working dir, for Solaris and derivatives, where rmdir()
        # on the current directory fails.
        os.chdir(self.old_cwd)
        super().tearDown()
        while self.tempdirs:
            d = self.tempdirs.pop()
            shutil.rmtree(d, os.name in ('nt', 'cygwin'))

    def mkdtemp(self):
        """Create a temporary directory that will be cleaned up.

        Returns the path of the directory.
        """
        d = tempfile.mkdtemp()
        self.tempdirs.append(d)
        return d

    def write_file(self, path, content='xxx'):
        """Writes a file in the given path.

        path can be a string or a sequence.
        """
        if isinstance(path, (list, tuple)):
            path = os.path.join(*path)
        f = open(path, 'w')
        try:
            f.write(content)
        finally:
            f.close()

    def create_dist(self, pkg_name='foo', **kw):
        """Will generate a test environment.

        This function creates:
         - a Distribution instance using keywords
         - a temporary directory with a package structure

        It returns the package directory and the distribution
        instance.
        """
        tmp_dir = self.mkdtemp()
        pkg_dir = os.path.join(tmp_dir, pkg_name)
        os.mkdir(pkg_dir)
        dist = Distribution(attrs=kw)

        return pkg_dir, dist

class DummyCommand:
    """Class to store options for retrieval via set_undefined_options()."""

    def __init__(self, **kwargs):
        for kw, val in kwargs.items():
            setattr(self, kw, val)

    def ensure_finalized(self):
        pass

class EnvironGuard(object):

    def setUp(self):
        super(EnvironGuard, self).setUp()
        self.old_environ = deepcopy(os.environ)

    def tearDown(self):
        for key, value in self.old_environ.items():
            if os.environ.get(key) != value:
                os.environ[key] = value

        for key in tuple(os.environ.keys()):
            if key not in self.old_environ:
                del os.environ[key]

        super(EnvironGuard, self).tearDown()

def copy_xxmodule_c(directory):
    """Helper for tests that need the xxmodule.c source file.

    Example use:

        def test_compile(self):
            copy_xxmodule_c(self.tmpdir)
            self.assertIn('xxmodule.c', os.listdir(self.tmpdir))

    If the source file can be found, it will be copied to *directory*.  If not,
    the test will be skipped.  Errors during copy are not caught.
    """
    filename = _get_xxmodule_path()
    if filename is None:
        raise unittest.SkipTest('cannot find xxmodule.c (test must run in '
                                'the python build dir)')
    shutil.copy(filename, directory)

def _get_xxmodule_path():
    srcdir = sysconfig.get_config_var('srcdir')
    candidates = [
        # use installed copy if available
        os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
        # otherwise try using copy from build directory
        os.path.join(srcdir, 'Modules', 'xxmodule.c'),
        # srcdir mysteriously can be $srcdir/Lib/distutils/tests when
        # this file is run from its parent directory, so walk up the
        # tree to find the real srcdir
        os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
    ]
    for path in candidates:
        if os.path.exists(path):
            return path

def fixup_build_ext(cmd):
    """Function needed to make build_ext tests pass.

    When Python was built with --enable-shared on Unix, -L. is not enough to
    find libpython<blah>.so, because regrtest runs in a tempdir, not in the
    source directory where the .so lives.

    When Python was built with in debug mode on Windows, build_ext commands
    need their debug attribute set, and it is not done automatically for
    some reason.

    This function handles both of these things.  Example use:

        cmd = build_ext(dist)
        support.fixup_build_ext(cmd)
        cmd.ensure_finalized()

    Unlike most other Unix platforms, Mac OS X embeds absolute paths
    to shared libraries into executables, so the fixup is not needed there.
    """
    if os.name == 'nt':
        cmd.debug = sys.executable.endswith('_d.exe')
    elif sysconfig.get_config_var('Py_ENABLE_SHARED'):
        # To further add to the shared builds fun on Unix, we can't just add
        # library_dirs to the Extension() instance because that doesn't get
        # plumbed through to the final compiler command.
        runshared = sysconfig.get_config_var('RUNSHARED')
        if runshared is None:
            cmd.library_dirs = ['.']
        else:
            if sys.platform == 'darwin':
                cmd.library_dirs = []
            else:
                name, equals, value = runshared.partition('=')
                cmd.library_dirs = value.split(os.pathsep)
<commit_msg>- Issue #17752: Fix distutils tests when run from the installed location.<commit_after>"""Support code for distutils test cases."""
import os
import sys
import shutil
import tempfile
import unittest
import sysconfig
from copy import deepcopy

from distutils import log
from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL
from distutils.core import Distribution

class LoggingSilencer(object):

    def setUp(self):
        super().setUp()
        self.threshold = log.set_threshold(log.FATAL)
        # catching warnings
        # when log will be replaced by logging
        # we won't need such monkey-patch anymore
        self._old_log = log.Log._log
        log.Log._log = self._log
        self.logs = []

    def tearDown(self):
        log.set_threshold(self.threshold)
        log.Log._log = self._old_log
        super().tearDown()

    def _log(self, level, msg, args):
        if level not in (DEBUG, INFO, WARN, ERROR, FATAL):
            raise ValueError('%s wrong log level' % str(level))
        if not isinstance(msg, str):
            raise TypeError("msg should be str, not '%.200s'"
                            % (type(msg).__name__))
        self.logs.append((level, msg, args))

    def get_logs(self, *levels):
        def _format(msg, args):
            return msg % args
        return [msg % args for level, msg, args
                in self.logs if level in levels]

    def clear_logs(self):
        self.logs = []

class TempdirManager(object):
    """Mix-in class that handles temporary directories for test cases.

    This is intended to be used with unittest.TestCase.
    """

    def setUp(self):
        super().setUp()
        self.old_cwd = os.getcwd()
        self.tempdirs = []

    def tearDown(self):
        # Restore working dir, for Solaris and derivatives, where rmdir()
        # on the current directory fails.
        os.chdir(self.old_cwd)
        super().tearDown()
        while self.tempdirs:
            d = self.tempdirs.pop()
            shutil.rmtree(d, os.name in ('nt', 'cygwin'))

    def mkdtemp(self):
        """Create a temporary directory that will be cleaned up.

        Returns the path of the directory.
        """
        d = tempfile.mkdtemp()
        self.tempdirs.append(d)
        return d

    def write_file(self, path, content='xxx'):
        """Writes a file in the given path.

        path can be a string or a sequence.
        """
        if isinstance(path, (list, tuple)):
            path = os.path.join(*path)
        f = open(path, 'w')
        try:
            f.write(content)
        finally:
            f.close()

    def create_dist(self, pkg_name='foo', **kw):
        """Will generate a test environment.

        This function creates:
         - a Distribution instance using keywords
         - a temporary directory with a package structure

        It returns the package directory and the distribution
        instance.
        """
        tmp_dir = self.mkdtemp()
        pkg_dir = os.path.join(tmp_dir, pkg_name)
        os.mkdir(pkg_dir)
        dist = Distribution(attrs=kw)

        return pkg_dir, dist

class DummyCommand:
    """Class to store options for retrieval via set_undefined_options()."""

    def __init__(self, **kwargs):
        for kw, val in kwargs.items():
            setattr(self, kw, val)

    def ensure_finalized(self):
        pass

class EnvironGuard(object):

    def setUp(self):
        super(EnvironGuard, self).setUp()
        self.old_environ = deepcopy(os.environ)

    def tearDown(self):
        for key, value in self.old_environ.items():
            if os.environ.get(key) != value:
                os.environ[key] = value

        for key in tuple(os.environ.keys()):
            if key not in self.old_environ:
                del os.environ[key]

        super(EnvironGuard, self).tearDown()

def copy_xxmodule_c(directory):
    """Helper for tests that need the xxmodule.c source file.

    Example use:

        def test_compile(self):
            copy_xxmodule_c(self.tmpdir)
            self.assertIn('xxmodule.c', os.listdir(self.tmpdir))

    If the source file can be found, it will be copied to *directory*.  If not,
    the test will be skipped.  Errors during copy are not caught.
    """
    filename = _get_xxmodule_path()
    if filename is None:
        raise unittest.SkipTest('cannot find xxmodule.c (test must run in '
                                'the python build dir)')
    shutil.copy(filename, directory)

def _get_xxmodule_path():
    srcdir = sysconfig.get_config_var('srcdir')
    candidates = [
        # use installed copy if available
        os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
        # otherwise try using copy from build directory
        os.path.join(srcdir, 'Modules', 'xxmodule.c'),
        # srcdir mysteriously can be $srcdir/Lib/distutils/tests when
        # this file is run from its parent directory, so walk up the
        # tree to find the real srcdir
        os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
    ]
    for path in candidates:
        if os.path.exists(path):
            return path

def fixup_build_ext(cmd):
    """Function needed to make build_ext tests pass.

    When Python was built with --enable-shared on Unix, -L. is not enough to
    find libpython<blah>.so, because regrtest runs in a tempdir, not in the
    source directory where the .so lives.

    When Python was built with in debug mode on Windows, build_ext commands
    need their debug attribute set, and it is not done automatically for
    some reason.

    This function handles both of these things.  Example use:

        cmd = build_ext(dist)
        support.fixup_build_ext(cmd)
        cmd.ensure_finalized()

    Unlike most other Unix platforms, Mac OS X embeds absolute paths
    to shared libraries into executables, so the fixup is not needed there.
    """
    if os.name == 'nt':
        cmd.debug = sys.executable.endswith('_d.exe')
    elif sysconfig.get_config_var('Py_ENABLE_SHARED'):
        # To further add to the shared builds fun on Unix, we can't just add
        # library_dirs to the Extension() instance because that doesn't get
        # plumbed through to the final compiler command.
        runshared = sysconfig.get_config_var('RUNSHARED')
        if runshared is None:
            cmd.library_dirs = ['.']
        else:
            if sys.platform == 'darwin':
                cmd.library_dirs = []
            else:
                name, equals, value = runshared.partition('=')
                cmd.library_dirs = [d for d in value.split(os.pathsep) if d]
<|endoftext|>


<commit_before>from .main import PGCli
import sql.parse
import sql.connection
import logging

_logger = logging.getLogger(__name__)

def load_ipython_extension(ipython):

    #This is called via the ipython command '%load_ext pgcli.magic'

    #first, load the sql magic if it isn't already loaded
    if not ipython.find_line_magic('sql'):
        ipython.run_line_magic('load_ext', 'sql')

    #register our own magic
    ipython.register_magic_function(pgcli_line_magic, 'line', 'pgcli')

def pgcli_line_magic(line):
    _logger.debug('pgcli magic called: %r', line)
    parsed = sql.parse.parse(line, {})
    conn = sql.connection.Connection.get(parsed['connection'])

    try:
        #A corresponding pgcli object already exists
        pgcli = conn._pgcli
        _logger.debug('Reusing existing pgcli')
    except AttributeError:
        #I can't figure out how to get the underylying psycopg2 connection
        #from the sqlalchemy connection, so just grab the url and make a
        #new connection
        pgcli = PGCli()
        u = conn.session.engine.url
        _logger.debug('New pgcli: %r', str(u))

        pgcli.connect(u.database, u.host, u.username, u.port, u.password)
        conn._pgcli = pgcli

    try:
        pgcli.run_cli()
    except SystemExit:
        pass

    if not pgcli.query_history:
        return

    q = pgcli.query_history[-1]
    if q.successful:
        ipython = get_ipython()
        return ipython.run_cell_magic('sql', line, q.query)

<commit_msg>don't rerun a query in ipython magic if it was mutating<commit_after>from .main import PGCli
import sql.parse
import sql.connection
import logging

_logger = logging.getLogger(__name__)

def load_ipython_extension(ipython):

    #This is called via the ipython command '%load_ext pgcli.magic'

    #first, load the sql magic if it isn't already loaded
    if not ipython.find_line_magic('sql'):
        ipython.run_line_magic('load_ext', 'sql')

    #register our own magic
    ipython.register_magic_function(pgcli_line_magic, 'line', 'pgcli')

def pgcli_line_magic(line):
    _logger.debug('pgcli magic called: %r', line)
    parsed = sql.parse.parse(line, {})
    conn = sql.connection.Connection.get(parsed['connection'])

    try:
        #A corresponding pgcli object already exists
        pgcli = conn._pgcli
        _logger.debug('Reusing existing pgcli')
    except AttributeError:
        #I can't figure out how to get the underylying psycopg2 connection
        #from the sqlalchemy connection, so just grab the url and make a
        #new connection
        pgcli = PGCli()
        u = conn.session.engine.url
        _logger.debug('New pgcli: %r', str(u))

        pgcli.connect(u.database, u.host, u.username, u.port, u.password)
        conn._pgcli = pgcli

    try:
        pgcli.run_cli()
    except SystemExit:
        pass

    if not pgcli.query_history:
        return

    q = pgcli.query_history[-1]
    if q.mutating:
        _logger.debug('Mutating query detected -- ignoring')
        return

    if q.successful:
        ipython = get_ipython()
        return ipython.run_cell_magic('sql', line, q.query)

<|endoftext|>


<commit_before># Copyright (c) 2017 The Regents of the University of Michigan
# All rights reserved.
# This software is licensed under the BSD 3-Clause License.
from __future__ import print_function

import warnings as _warnings
import os as _os
import sys as _sys

from tempfile import mkdtemp

class TemporaryDirectory(object):
    """Create and return a temporary directory.  This has the same
    behavior as mkdtemp but can be used as a context manager.  For
    example:

        with TemporaryDirectory() as tmpdir:
            ...

    Upon exiting the context, the directory and everything contained
    in it are removed.
    """

    def __init__(self, suffix="", prefix="tmp", dir=None):
        self._closed = False
        self.name = None  # Handle mkdtemp raising an exception
        self.name = mkdtemp(suffix, prefix, dir)

    def __repr__(self):
        return "<{} {!r}>".format(self.__class__.__name__, self.name)

    def __enter__(self):
        return self.name

    def cleanup(self, _warn=False):
        if self.name and not self._closed:
            try:
                self._rmtree(self.name)
            except (TypeError, AttributeError) as ex:
                # Issue #10188: Emit a warning on stderr
                # if the directory could not be cleaned
                # up due to missing globals
                if "None" not in str(ex):
                    raise
                print("ERROR: {!r} while cleaning up {!r}".format(ex, self,),
                      file=_sys.stderr)
                return
            self._closed = True
            if _warn:
                self._warn("Implicitly cleaning up {!r}".format(self),
                           ResourceWarning)

    def __exit__(self, exc, value, tb):
        self.cleanup()

    def __del__(self):
        # Issue a ResourceWarning if implicit cleanup needed
        self.cleanup(_warn=True)

    # XXX (ncoghlan): The following code attempts to make
    # this class tolerant of the module nulling out process
    # that happens during CPython interpreter shutdown
    # Alas, it doesn't actually manage it. See issue #10188
    _listdir = staticmethod(_os.listdir)
    _path_join = staticmethod(_os.path.join)
    _isdir = staticmethod(_os.path.isdir)
    _islink = staticmethod(_os.path.islink)
    _remove = staticmethod(_os.remove)
    _rmdir = staticmethod(_os.rmdir)
    _warn = _warnings.warn

    def _rmtree(self, path):
        # Essentially a stripped down version of shutil.rmtree.  We can't
        # use globals because they may be None'ed out at shutdown.
        for name in self._listdir(path):
            fullname = self._path_join(path, name)
            try:
                isdir = self._isdir(fullname) and not self._islink(fullname)
            except OSError:
                isdir = False
            if isdir:
                self._rmtree(fullname)
            else:
                try:
                    self._remove(fullname)
                except OSError:
                    pass
        try:
            self._rmdir(path)
        except OSError:
            pass

if __name__ == '__main__':
    import os
    with TemporaryDirectory() as tmp_dir:
        print("Temporary directory path: %s" % tmp_dir)
        print(os.path.isdir(tmp_dir))

# here the temporary diretory does not exist any more.
    print(os.path.isdir(tmp_dir))
<commit_msg>Fix licensing statement in external tempdir module.<commit_after>"""Backports the TemporaryDirectoy class for Python 2.7.

Source: https://stackoverflow.com/a/19299884
"""
from __future__ import print_function

import warnings as _warnings
import os as _os
import sys as _sys

from tempfile import mkdtemp

class TemporaryDirectory(object):
    """Create and return a temporary directory.  This has the same
    behavior as mkdtemp but can be used as a context manager.  For
    example:

        with TemporaryDirectory() as tmpdir:
            ...

    Upon exiting the context, the directory and everything contained
    in it are removed.
    """

    def __init__(self, suffix="", prefix="tmp", dir=None):
        self._closed = False
        self.name = None  # Handle mkdtemp raising an exception
        self.name = mkdtemp(suffix, prefix, dir)

    def __repr__(self):
        return "<{} {!r}>".format(self.__class__.__name__, self.name)

    def __enter__(self):
        return self.name

    def cleanup(self, _warn=False):
        if self.name and not self._closed:
            try:
                self._rmtree(self.name)
            except (TypeError, AttributeError) as ex:
                # Issue #10188: Emit a warning on stderr
                # if the directory could not be cleaned
                # up due to missing globals
                if "None" not in str(ex):
                    raise
                print("ERROR: {!r} while cleaning up {!r}".format(ex, self,),
                      file=_sys.stderr)
                return
            self._closed = True
            if _warn:
                self._warn("Implicitly cleaning up {!r}".format(self),
                           ResourceWarning)

    def __exit__(self, exc, value, tb):
        self.cleanup()

    def __del__(self):
        # Issue a ResourceWarning if implicit cleanup needed
        self.cleanup(_warn=True)

    # XXX (ncoghlan): The following code attempts to make
    # this class tolerant of the module nulling out process
    # that happens during CPython interpreter shutdown
    # Alas, it doesn't actually manage it. See issue #10188
    _listdir = staticmethod(_os.listdir)
    _path_join = staticmethod(_os.path.join)
    _isdir = staticmethod(_os.path.isdir)
    _islink = staticmethod(_os.path.islink)
    _remove = staticmethod(_os.remove)
    _rmdir = staticmethod(_os.rmdir)
    _warn = _warnings.warn

    def _rmtree(self, path):
        # Essentially a stripped down version of shutil.rmtree.  We can't
        # use globals because they may be None'ed out at shutdown.
        for name in self._listdir(path):
            fullname = self._path_join(path, name)
            try:
                isdir = self._isdir(fullname) and not self._islink(fullname)
            except OSError:
                isdir = False
            if isdir:
                self._rmtree(fullname)
            else:
                try:
                    self._remove(fullname)
                except OSError:
                    pass
        try:
            self._rmdir(path)
        except OSError:
            pass

if __name__ == '__main__':
    import os
    with TemporaryDirectory() as tmp_dir:
        print("Temporary directory path: %s" % tmp_dir)
        print(os.path.isdir(tmp_dir))

# here the temporary diretory does not exist any more.
    print(os.path.isdir(tmp_dir))
<|endoftext|>


<commit_before>#!/usr/bin/env ccp4-python
"""Script to run all the AMPLE tests"""
import os
import sys
import unittest

###############################################################
#
# Add the python directory to the path
#
###############################################################
thisd =  os.path.abspath( os.path.dirname( __file__ ) )
paths = thisd.split( os.sep )
ampleDir = os.sep.join( paths[ : -1 ] )
sys.path.insert(0,os.path.join( ampleDir,'python'))

###############################################################
#
# The testsuite to hold the series of tests that we will run
#
###############################################################
testsuite = unittest.TestSuite()

###############################################################
#
# Add all the tests
#
###############################################################
import ample_ensemble
testsuite.addTests(ample_ensemble.testSuite())

import csymmatch
testsuite.addTests(csymmatch.testSuite())

import dssp
testsuite.addTests(dssp.testSuite())

import ensemble
testsuite.addTests(ensemble.testSuite())

import fasta_parser
testsuite.addTests(fasta_parser.testSuite())

import mtz_util
testsuite.addTests(mtz_util.testSuite())

import octopus_predict
testsuite.addTests(octopus_predict.testSuite())

import parse_arpwarp
testsuite.addTests(parse_arpwarp.testSuite())

import parse_buccaneer
testsuite.addTests(parse_buccaneer.testSuite())

import parse_phaser
testsuite.addTests(parse_phaser.testSuite())

import parse_refmac
testsuite.addTests(parse_refmac.testSuite())

import pdb_edit
testsuite.addTests(pdb_edit.testSuite())

import pdb_model
testsuite.addTests(pdb_model.testSuite())

import residue_map
testsuite.addTests(residue_map.testSuite())

import rio
testsuite.addTests(rio.testSuite())

import rosetta_model
testsuite.addTests(rosetta_model.testSuite())

import subcluster
testsuite.addTests(subcluster.testSuite())

import workers
testsuite.addTests(workers.testSuite())

###############################################################
#
# Now run 'em all
#
###############################################################
unittest.TextTestRunner(verbosity=2).run(testsuite)
<commit_msg>Remove parser tests<commit_after>#!/usr/bin/env ccp4-python
"""Script to run all the AMPLE tests"""
import os
import sys
import unittest

###############################################################
#
# Add the python directory to the path
#
###############################################################
thisd =  os.path.abspath( os.path.dirname( __file__ ) )
paths = thisd.split( os.sep )
ampleDir = os.sep.join( paths[ : -1 ] )
sys.path.insert(0,os.path.join( ampleDir,'python'))

###############################################################
#
# The testsuite to hold the series of tests that we will run
#
###############################################################
testsuite = unittest.TestSuite()

###############################################################
#
# Add all the tests
#
###############################################################
import ample_ensemble
testsuite.addTests(ample_ensemble.testSuite())

import csymmatch
testsuite.addTests(csymmatch.testSuite())

import dssp
testsuite.addTests(dssp.testSuite())

import ensemble
testsuite.addTests(ensemble.testSuite())

import fasta_parser
testsuite.addTests(fasta_parser.testSuite())

import mtz_util
testsuite.addTests(mtz_util.testSuite())

import octopus_predict
testsuite.addTests(octopus_predict.testSuite())

import pdb_edit
testsuite.addTests(pdb_edit.testSuite())

import pdb_model
testsuite.addTests(pdb_model.testSuite())

import residue_map
testsuite.addTests(residue_map.testSuite())

import rio
testsuite.addTests(rio.testSuite())

import rosetta_model
testsuite.addTests(rosetta_model.testSuite())

import subcluster
testsuite.addTests(subcluster.testSuite())

import workers
testsuite.addTests(workers.testSuite())

###############################################################
#
# Now run 'em all
#
###############################################################
unittest.TextTestRunner(verbosity=2).run(testsuite)
<|endoftext|>


<commit_before>from __future__ import division
import os
import numpy as np
import scipy
import scipy.misc
import scipy.cluster
import matplotlib
matplotlib.use('Agg')
import Image
import sqlite3
from utils import memo
import color_spaces as cs
from directory_walker import DirectoryWalker

def salient_colors(img, clusters=4, size=100):
    """Group the colors in an image into like clusters, and return a list
    of these colors in order of their abundance in the image."""
    assert img.mode == 'RGB', 'RGB images only!'
    img.thumbnail((size, size))
    imgarr = scipy.misc.fromimage(img)
    imgarr = imgarr.reshape(scipy.product(imgarr.shape[:2]), imgarr.shape[2])
    colors, dist = scipy.cluster.vq.kmeans(imgarr, clusters)
    vecs, dist = scipy.cluster.vq.vq(imgarr, colors)
    counts, bins = scipy.histogram(vecs, len(colors))
    ranked_colors = colors[(-counts).argsort()]
    return ranked_colors

def create_image_pool(image_dir, db_name='imagepool.db'):
    """Analyze all the images in image_dir, and store the results in
    a sqlite database at db_name."""
    db = connect(os.path.join(image_dir, db_name))
    try:
        create_tables(db)
        walker = DirectoryWalker(image_dir)
        for filename in walker:
            try:
                img = Image.open(filename)
            except IOError:
                print 'Cannot open %s as an image. Skipping it.' % filename
                continue
            if img.mode != 'RGB':
                print 'RGB images only. Skipping %s.' % filename
                continue
            w, h = img.size
            rgb_colors = salient_colors(img)
            lab_colors = map(cs.rgb2lab, rgb_colors)
            insert(filename, w, h, rgb_colors, lab_colors, db)
        db.commit()
        print '%s commited to database.' % filename
    finally:
        db.close()

def print_db(db):
    "Dump the database to the screen, for debugging."
    c = db.cursor()
    c.execute("SELECT * FROM Images")
    for row in c:
        print row
    c.execute("SELECT * FROM Colors")
    for row in c:
        print row
    c.close()

def insert(filename, w, h, rgb, lab, db):
    "Register an image in Images and its salient colors in Colors."
    c = db.cursor()
    try:
        c.execute("""INSERT INTO Images (usages, w, h, filename)
                     VALUES (?, ?, ?, ?)""",
                  (0, w, h, filename))
        image_id = c.lastrowid
        for i in xrange(len(rgb)):
            red, green, blue = map(int, rgb[i]) # np.uint8 confuses sqlite3
            L, a, b = lab[i]
            rank = 1 + i
            c.execute("""INSERT INTO Colors (image_id, rank,
                         L, a, b, red, green, blue)
                         VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
                         (image_id, rank, L, a, b, red, green, blue))
    except sqlite3.IntegrityError:
        print "Image %s is already in the table. Skipping it." % filename
    finally:
        c.close()

def connect(db_path):
    "Connect to, and if need be create, a sqlite database at db_path."
    try:
        db = sqlite3.connect(db_path)
    except IOError:
        print 'Cannot connect to SQLite database at %s' % db_path
        return
    db.row_factory = sqlite3.Row
    return db

def create_tables(db):
    c = db.cursor()
    c.execute("""CREATE TABLE IF NOT EXISTS Images
                 (image_id INTEGER PRIMARY KEY,
                  usages INTEGER,
                  w INTEGER,
                  h INTEGER,
                  filename TEXT UNIQUE)""")
    c.execute("""CREATE TABLE IF NOT EXISTS Colors
                 (color_id INTEGER PRIMARY KEY,
                  image_id INTEGER,
                  rank INTEGER,
                  L REAL,
                  a REAL,
                  b REAL,
                  red INTEGER,
                  green INTEGER,
                  blue INTEGER)""")
    c.close()
    db.commit()

def photomosaic(target_filename, tile_size, db_path):
    """Given the filename of the target image,
    the desired size (w, h) of a tile,
    and the path for a database generated by create_image_pool,
    return a photomosaic image."""
    try:
        target_img = Image.open(target_filename)
    except IOError:
        print "Cannot open %s as an image." % target_filename
        return 1
    tiles = partition_target(target_img, tile_size)
    db = connect(db_path)
    try:
        reset_usage(db)
        for x, row in enumerate(tiles):
            for y, tile in enumerate(row):
                # Replace target tile with a matched tile.
                tiles[x][y] = make_tile(find_match(tile, db), tile_size)
    finally:
        db.close()
    mosaic = assemble_mosaic(tiles, tile_size)
    return mosaic

def reset_usage(db):
    "Before using the image pool, reset image usage count to 0."
    try:
        c = db.cursor()
        c.execute("UPDATE Images SET usages=0")
        c.close()
        db.commit()
    except sqlite3.OperationalError, e:
        print e

def partition_target(img, tile_size):
    "Partition the target image into a 2D list of Images."
    # TODO: Allow to tiles are different sizes.
    # Merge neighbors that are similar
    # or that inhabit regions of long spatial wavelength.
    width = img.size[0] // tile_size[0]
    height = img.size[1] // tile_size[1]
    tiles = [[None for w in range(width)] for h in range(height)]
    for y in range(height):
        for x in range(width):
            tile = img.crop((x*tile_size[0],
                             y*tile_size[1],
                             (x + 1)*tile_size[0],
                             (y + 1)*tile_size[1]))
            tiles[y][x] = tile
    return tiles

def assemble_mosaic(tiles, tile_size):
    "Build the final image."
    # Technically, tile_size could be inferred from a tile,
    # but let's not trust it in this case.
    size = len(tiles[0])*tile_size[0], len(tiles)*tile_size[1]
    mosaic = Image.new('RGB', size)
    for y, row in enumerate(tiles):
        for x, tile in enumerate(row):
            pos = x*tile_size[0], y*tile_size[1]
            mosaic.paste(tile, pos)
    return mosaic # suitable to be saved with imsave

def find_match(tile, db, max_usages=5):
    """Query the db for the best match, weighing the color's ab-distance
    in Lab color space, the color's prominence in the image in question
    (its 'rank'), and the image's usage count."""
    target_l, target_a, target_b = map(rgb2lab, salient_colors(tile))[0]
    LIMIT = 10
    # Here, I am working around sqlite's lack of ^ and sqrt operations.
    try:
        c = db.cursor()
        c.execute("""SELECT
                     image_id,
                     L, a, b,
                     (a-?)*(a-?) + (b-?)*(b-?) as ab_distance,
                     rank,
                     usages,
                     filename
                     FROM Colors
                     JOIN Images USING (image_id)
                     WHERE usages <= ?
                     ORDER BY ab_distance ASC
                     LIMIT ?""",
                  (target_a, target_a, target_b, target_b, max_usages, LIMIT))
        match = c.fetchone()
        c.execute("""UPDATE Images SET usages=usages+1 WHERE image_id=?""", (match['image_id'],))
    finally:
        c.close()
    return match # a sqlite3.Row object

def make_tile(match, tile_size):
    "Open and resize the matched image."
    raw = Image.open(match['filename'])
    img = crop_to_fit(raw, tile_size)
    return img

def crop_to_fit(img, tile_size):
    "Return a copy of img cropped to precisely fill the dimesions tile_size."
    img_w, img_h = img.size
    tile_w, tile_h = tile_size
    img_aspect = img_w // img_h
    tile_aspect = tile_w // tile_h
    if img_aspect > tile_aspect:
        crop_h = img_h
        crop_w = crop_h*tile_aspect
        x_offset = (img_w - crop_width) // 2
        y_offset = 0
    else:
        crop_w = img_w
        crop_h = crop_w // tile_aspect
        x_offset = 0
        y_offset = (img_h - crop_h) // 2
    img = img.crop((x_offset,
                    y_offset,
                    x_offset + crop_w,
                    y_offset + crop_h))
    img = img.resize((tile_w, tile_h), Image.ANTIALIAS)
    return img

def color_hex(rgb):
    "Convert [r, g, b] to a HEX value with a leading # character."
    return '#' ''.join(chr(c) for c in color).encode('hex')

def Lab_distance(lab1, lab2):
    """Compute distance in Lab."""
    L1, a1, b1 = lab1
    L2, a2, b2 = lab2
    E = sqrt((L1 - L2)**2 + (a1 - a2)**2 + (b1 - b2)**2)
    return E

def ab_distance(lab1, lab2):
    """Compute distance in the a-b plane, disregarding L."""
    L1, a1, b1 = lab1
    L2, a2, b2 = lab2
    return sqrt((a1-a2)**2 + (b1-b2)**2)
<commit_msg>Slightly less verbose.<commit_after>from __future__ import division
import os
import numpy as np
import scipy
import scipy.misc
import scipy.cluster
import matplotlib
matplotlib.use('Agg')
import Image
import sqlite3
from utils import memo
import color_spaces as cs
from directory_walker import DirectoryWalker

def salient_colors(img, clusters=4, size=100):
    """Group the colors in an image into like clusters, and return a list
    of these colors in order of their abundance in the image."""
    assert img.mode == 'RGB', 'RGB images only!'
    img.thumbnail((size, size))
    imgarr = scipy.misc.fromimage(img)
    imgarr = imgarr.reshape(scipy.product(imgarr.shape[:2]), imgarr.shape[2])
    colors, dist = scipy.cluster.vq.kmeans(imgarr, clusters)
    vecs, dist = scipy.cluster.vq.vq(imgarr, colors)
    counts, bins = scipy.histogram(vecs, len(colors))
    ranked_colors = colors[(-counts).argsort()]
    return ranked_colors

def create_image_pool(image_dir, db_name='imagepool.db'):
    """Analyze all the images in image_dir, and store the results in
    a sqlite database at db_name."""
    db = connect(os.path.join(image_dir, db_name))
    try:
        create_tables(db)
        walker = DirectoryWalker(image_dir)
        for filename in walker:
            try:
                img = Image.open(filename)
            except IOError:
                print 'Cannot open %s as an image. Skipping it.' % filename
                continue
            if img.mode != 'RGB':
                print 'RGB images only. Skipping %s.' % filename
                continue
            w, h = img.size
            rgb_colors = salient_colors(img)
            lab_colors = map(cs.rgb2lab, rgb_colors)
            insert(filename, w, h, rgb_colors, lab_colors, db)
        db.commit()
    finally:
        db.close()

def print_db(db):
    "Dump the database to the screen, for debugging."
    c = db.cursor()
    c.execute("SELECT * FROM Images")
    for row in c:
        print row
    c.execute("SELECT * FROM Colors")
    for row in c:
        print row
    c.close()

def insert(filename, w, h, rgb, lab, db):
    "Register an image in Images and its salient colors in Colors."
    c = db.cursor()
    try:
        c.execute("""INSERT INTO Images (usages, w, h, filename)
                     VALUES (?, ?, ?, ?)""",
                  (0, w, h, filename))
        image_id = c.lastrowid
        for i in xrange(len(rgb)):
            red, green, blue = map(int, rgb[i]) # np.uint8 confuses sqlite3
            L, a, b = lab[i]
            rank = 1 + i
            c.execute("""INSERT INTO Colors (image_id, rank,
                         L, a, b, red, green, blue)
                         VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
                         (image_id, rank, L, a, b, red, green, blue))
    except sqlite3.IntegrityError:
        print "Image %s is already in the table. Skipping it." % filename
    finally:
        c.close()

def connect(db_path):
    "Connect to, and if need be create, a sqlite database at db_path."
    try:
        db = sqlite3.connect(db_path)
    except IOError:
        print 'Cannot connect to SQLite database at %s' % db_path
        return
    db.row_factory = sqlite3.Row
    return db

def create_tables(db):
    c = db.cursor()
    c.execute("""CREATE TABLE IF NOT EXISTS Images
                 (image_id INTEGER PRIMARY KEY,
                  usages INTEGER,
                  w INTEGER,
                  h INTEGER,
                  filename TEXT UNIQUE)""")
    c.execute("""CREATE TABLE IF NOT EXISTS Colors
                 (color_id INTEGER PRIMARY KEY,
                  image_id INTEGER,
                  rank INTEGER,
                  L REAL,
                  a REAL,
                  b REAL,
                  red INTEGER,
                  green INTEGER,
                  blue INTEGER)""")
    c.close()
    db.commit()

def photomosaic(target_filename, tile_size, db_path):
    """Given the filename of the target image,
    the desired size (w, h) of a tile,
    and the path for a database generated by create_image_pool,
    return a photomosaic image."""
    try:
        target_img = Image.open(target_filename)
    except IOError:
        print "Cannot open %s as an image." % target_filename
        return 1
    tiles = partition_target(target_img, tile_size)
    db = connect(db_path)
    try:
        reset_usage(db)
        for x, row in enumerate(tiles):
            for y, tile in enumerate(row):
                # Replace target tile with a matched tile.
                tiles[x][y] = make_tile(find_match(tile, db), tile_size)
    finally:
        db.close()
    mosaic = assemble_mosaic(tiles, tile_size)
    return mosaic

def reset_usage(db):
    "Before using the image pool, reset image usage count to 0."
    try:
        c = db.cursor()
        c.execute("UPDATE Images SET usages=0")
        c.close()
        db.commit()
    except sqlite3.OperationalError, e:
        print e

def partition_target(img, tile_size):
    "Partition the target image into a 2D list of Images."
    # TODO: Allow to tiles are different sizes.
    # Merge neighbors that are similar
    # or that inhabit regions of long spatial wavelength.
    width = img.size[0] // tile_size[0]
    height = img.size[1] // tile_size[1]
    tiles = [[None for w in range(width)] for h in range(height)]
    for y in range(height):
        for x in range(width):
            tile = img.crop((x*tile_size[0],
                             y*tile_size[1],
                             (x + 1)*tile_size[0],
                             (y + 1)*tile_size[1]))
            tiles[y][x] = tile
    return tiles

def assemble_mosaic(tiles, tile_size):
    "Build the final image."
    # Technically, tile_size could be inferred from a tile,
    # but let's not trust it in this case.
    size = len(tiles[0])*tile_size[0], len(tiles)*tile_size[1]
    mosaic = Image.new('RGB', size)
    for y, row in enumerate(tiles):
        for x, tile in enumerate(row):
            pos = x*tile_size[0], y*tile_size[1]
            mosaic.paste(tile, pos)
    return mosaic # suitable to be saved with imsave

def find_match(tile, db, max_usages=5):
    """Query the db for the best match, weighing the color's ab-distance
    in Lab color space, the color's prominence in the image in question
    (its 'rank'), and the image's usage count."""
    target_l, target_a, target_b = map(rgb2lab, salient_colors(tile))[0]
    LIMIT = 10
    # Here, I am working around sqlite's lack of ^ and sqrt operations.
    try:
        c = db.cursor()
        c.execute("""SELECT
                     image_id,
                     L, a, b,
                     (a-?)*(a-?) + (b-?)*(b-?) as ab_distance,
                     rank,
                     usages,
                     filename
                     FROM Colors
                     JOIN Images USING (image_id)
                     WHERE usages <= ?
                     ORDER BY ab_distance ASC
                     LIMIT ?""",
                  (target_a, target_a, target_b, target_b, max_usages, LIMIT))
        match = c.fetchone()
        c.execute("""UPDATE Images SET usages=usages+1 WHERE image_id=?""", (match['image_id'],))
    finally:
        c.close()
    return match # a sqlite3.Row object

def make_tile(match, tile_size):
    "Open and resize the matched image."
    raw = Image.open(match['filename'])
    img = crop_to_fit(raw, tile_size)
    return img

def crop_to_fit(img, tile_size):
    "Return a copy of img cropped to precisely fill the dimesions tile_size."
    img_w, img_h = img.size
    tile_w, tile_h = tile_size
    img_aspect = img_w // img_h
    tile_aspect = tile_w // tile_h
    if img_aspect > tile_aspect:
        crop_h = img_h
        crop_w = crop_h*tile_aspect
        x_offset = (img_w - crop_width) // 2
        y_offset = 0
    else:
        crop_w = img_w
        crop_h = crop_w // tile_aspect
        x_offset = 0
        y_offset = (img_h - crop_h) // 2
    img = img.crop((x_offset,
                    y_offset,
                    x_offset + crop_w,
                    y_offset + crop_h))
    img = img.resize((tile_w, tile_h), Image.ANTIALIAS)
    return img

def color_hex(rgb):
    "Convert [r, g, b] to a HEX value with a leading # character."
    return '#' ''.join(chr(c) for c in color).encode('hex')

def Lab_distance(lab1, lab2):
    """Compute distance in Lab."""
    L1, a1, b1 = lab1
    L2, a2, b2 = lab2
    E = sqrt((L1 - L2)**2 + (a1 - a2)**2 + (b1 - b2)**2)
    return E

def ab_distance(lab1, lab2):
    """Compute distance in the a-b plane, disregarding L."""
    L1, a1, b1 = lab1
    L2, a2, b2 = lab2
    return sqrt((a1-a2)**2 + (b1-b2)**2)
<|endoftext|>


<commit_before>import unittest

# Ugh. Settings for Django.
from django.conf import settings
settings.configure(DEBUG=True)

from restless.dj import DjangoResource
from restless.exceptions import MethodNotImplemented, Unauthorized
from restless.utils import json

from .fakes import FakeHttpRequest, FakeModel

class DjTestResource(DjangoResource):
    fields = {
        'id': 'id',
        'title': 'title',
        'author': 'username',
        'body': 'content'
    }
    fake_db = []

    def __init__(self, *args, **kwargs):
        super(DjTestResource, self).__init__(*args, **kwargs)

        self.http_methods.update({
            'schema': {
                'GET': 'schema',
            }
        })

    def fake_init(self):
        # Just for testing.
        self.__class__.fake_db = [
            FakeModel(id=2, title='First post', username='daniel', content='Hello world!'),
            FakeModel(id=4, title='Another', username='daniel', content='Stuff here.'),
            FakeModel(id=5, title='Last', username='daniel', content="G'bye!"),
        ]

    def is_authenticated(self):
        if self.request_method() == 'DELETE':
            return False

        return True

    def list(self):
        return self.fake_db

    def detail(self, pk):
        for item in self.fake_db:
            if item.id == pk:
                return item

    def create(self):
        self.fake_db.append(FakeModel(
            **self.data
        ))

    def update(self, pk):
        for item in self.fake_db:
            if item.id == pk:
                for k, v in self.data:
                    setattr(item, k, v)
                    return

    def create_detail(self):
        raise ValueError("This is a random & crazy exception.")

    def schema(self):
        # A WILD SCHEMA VIEW APPEARS!
        return {
            'fields': {
                'id': {
                    'type': 'integer',
                    'required': True,
                    'help_text': 'The unique id for the post',
                },
                'title': {
                    'type': 'string',
                    'required': True,
                    'help_text': "The post's title",
                },
                'author': {
                    'type': 'string',
                    'required': True,
                    'help_text': 'The username of the author of the post',
                },
                'body': {
                    'type': 'string',
                    'required': False,
                    'default': '',
                    'help_text': 'The content of the post',
                }
            },
            'format': 'application/json',
            'allowed_list_http_methods': ['GET', 'POST'],
            'allowed_detail_http_methods': ['GET', 'PUT', 'DELETE'],
        }

class DjangoResourceTestCase(unittest.TestCase):
    def setUp(self):
        super(DjangoResourceTestCase, self).setUp()
        self.res = DjTestResource()
        # Just for the fake data.
        self.res.fake_init()

    def test_as_list(self):
        list_endpoint = DjTestResource.as_list()
        req = FakeHttpRequest('GET')

        resp = list_endpoint(req)
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(json.loads(resp.content.decode('utf-8')), {
            'objects': [
                {
                    'author': 'daniel',
                    'body': 'Hello world!',
                    'id': 2,
                    'title': 'First post'
                },
                {
                    'author': 'daniel',
                    'body': 'Stuff here.',
                    'id': 4,
                    'title': 'Another'
                },
                {
                    'author': 'daniel',
                    'body': "G'bye!",
                    'id': 5,
                    'title': 'Last'
                }
            ]
        })

    def test_as_detail(self):
        detail_endpoint = DjTestResource.as_detail()
        req = FakeHttpRequest('GET')

        resp = detail_endpoint(req, 4)
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(json.loads(resp.content.decode('utf-8')), {
            'author': 'daniel',
            'body': 'Stuff here.',
            'id': 4,
            'title': 'Another'
        })

    def test_as_view(self):
        # This would be hooked up via the URLconf...
        schema_endpoint = DjTestResource.as_view('schema', prepare_data=False)
        req = FakeHttpRequest('GET')

        resp = schema_endpoint(req)
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 200)
        schema = json.loads(resp.content.decode('utf-8'))
        self.assertEqual(
            sorted(list(schema['fields'].keys())),
            [
                'author',
                'body',
                'id',
                'title',
            ]
        )
        self.assertEqual(schema['fields']['id']['type'], 'integer')
        self.assertEqual(schema['format'], 'application/json')

    def test_handle_not_implemented(self):
        self.res.request = FakeHttpRequest('TRACE')

        with self.assertRaises(MethodNotImplemented):
            self.res.handle('list')

    def test_handle_not_authenticated(self):
        # Special-cased above for testing.
        self.res.request = FakeHttpRequest('DELETE')

        with self.assertRaises(Unauthorized):
            self.res.handle('list')

    def test_handle_build_err(self):
        # Special-cased above for testing.
        self.res.request = FakeHttpRequest('POST')
        settings.DEBUG = False
        self.addCleanup(setattr, settings, 'DEBUG', True)

        resp = self.res.handle('detail')
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 500)
        self.assertEqual(json.loads(resp.content.decode('utf-8')), {
            'error': 'This is a random & crazy exception.'
        })

    def test_build_url_name(self):
        self.assertEqual(
            DjTestResource.build_url_name('list'),
            'api_djtest_list'
        )
        self.assertEqual(
            DjTestResource.build_url_name('detail'),
            'api_djtest_detail'
        )
        self.assertEqual(
            DjTestResource.build_url_name('schema'),
            'api_djtest_schema'
        )

        self.assertEqual(
            DjTestResource.build_url_name('list', name_prefix='v2_'),
            'v2_list'
        )
        self.assertEqual(
            DjTestResource.build_url_name('detail', name_prefix='v2_'),
            'v2_detail'
        )
        self.assertEqual(
            DjTestResource.build_url_name('schema', name_prefix='v2_'),
            'v2_schema'
        )

    def test_urls(self):
        patterns = DjTestResource.urls()
        self.assertEqual(len(patterns), 2)
        self.assertEqual(patterns[0].name, 'api_djtest_list')
        self.assertEqual(patterns[1].name, 'api_djtest_detail')

        patterns = DjTestResource.urls(name_prefix='v2_tests')
        self.assertEqual(len(patterns), 2)
        self.assertEqual(patterns[0].name, 'v2_tests_list')
        self.assertEqual(patterns[1].name, 'v2_tests_detail')

    def test_create(self):
        self.res.request = FakeHttpRequest('POST', body='{"id": 6, "title": "Moved hosts", "author": "daniel"}')
        self.assertEqual(len(self.res.fake_db), 3)

        resp = self.res.handle('list')
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 201)
        self.assertEqual(resp.content.decode('utf-8'), '')

        # Check the internal state.
        self.assertEqual(len(self.res.fake_db), 4)
        self.assertEqual(self.res.data, {
            'author': 'daniel',
            'id': 6,
            'title': 'Moved hosts'
        })
<commit_msg>Added tests covering the behavior from #4.<commit_after>import unittest

# Ugh. Settings for Django.
from django.conf import settings
settings.configure(DEBUG=True)

from restless.dj import DjangoResource
from restless.exceptions import MethodNotImplemented, Unauthorized
from restless.utils import json

from .fakes import FakeHttpRequest, FakeModel

class DjTestResource(DjangoResource):
    fields = {
        'id': 'id',
        'title': 'title',
        'author': 'username',
        'body': 'content'
    }
    fake_db = []

    def __init__(self, *args, **kwargs):
        super(DjTestResource, self).__init__(*args, **kwargs)

        self.http_methods.update({
            'schema': {
                'GET': 'schema',
            }
        })

    def fake_init(self):
        # Just for testing.
        self.__class__.fake_db = [
            FakeModel(id=2, title='First post', username='daniel', content='Hello world!'),
            FakeModel(id=4, title='Another', username='daniel', content='Stuff here.'),
            FakeModel(id=5, title='Last', username='daniel', content="G'bye!"),
        ]

    def is_authenticated(self):
        if self.request_method() == 'DELETE':
            return False

        return True

    def list(self):
        return self.fake_db

    def detail(self, pk):
        for item in self.fake_db:
            if item.id == pk:
                return item

    def create(self):
        self.fake_db.append(FakeModel(
            **self.data
        ))

    def update(self, pk):
        for item in self.fake_db:
            if item.id == pk:
                for k, v in self.data:
                    setattr(item, k, v)
                    return

    def create_detail(self):
        raise ValueError("This is a random & crazy exception.")

    def schema(self):
        # A WILD SCHEMA VIEW APPEARS!
        return {
            'fields': {
                'id': {
                    'type': 'integer',
                    'required': True,
                    'help_text': 'The unique id for the post',
                },
                'title': {
                    'type': 'string',
                    'required': True,
                    'help_text': "The post's title",
                },
                'author': {
                    'type': 'string',
                    'required': True,
                    'help_text': 'The username of the author of the post',
                },
                'body': {
                    'type': 'string',
                    'required': False,
                    'default': '',
                    'help_text': 'The content of the post',
                }
            },
            'format': 'application/json',
            'allowed_list_http_methods': ['GET', 'POST'],
            'allowed_detail_http_methods': ['GET', 'PUT', 'DELETE'],
        }

class DjangoResourceTestCase(unittest.TestCase):
    def setUp(self):
        super(DjangoResourceTestCase, self).setUp()
        self.res = DjTestResource()
        # Just for the fake data.
        self.res.fake_init()

    def test_as_list(self):
        list_endpoint = DjTestResource.as_list()
        req = FakeHttpRequest('GET')

        resp = list_endpoint(req)
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(json.loads(resp.content.decode('utf-8')), {
            'objects': [
                {
                    'author': 'daniel',
                    'body': 'Hello world!',
                    'id': 2,
                    'title': 'First post'
                },
                {
                    'author': 'daniel',
                    'body': 'Stuff here.',
                    'id': 4,
                    'title': 'Another'
                },
                {
                    'author': 'daniel',
                    'body': "G'bye!",
                    'id': 5,
                    'title': 'Last'
                }
            ]
        })

    def test_as_detail(self):
        detail_endpoint = DjTestResource.as_detail()
        req = FakeHttpRequest('GET')

        resp = detail_endpoint(req, 4)
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(json.loads(resp.content.decode('utf-8')), {
            'author': 'daniel',
            'body': 'Stuff here.',
            'id': 4,
            'title': 'Another'
        })

    def test_as_view(self):
        # This would be hooked up via the URLconf...
        schema_endpoint = DjTestResource.as_view('schema', prepare_data=False)
        req = FakeHttpRequest('GET')

        resp = schema_endpoint(req)
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 200)
        schema = json.loads(resp.content.decode('utf-8'))
        self.assertEqual(
            sorted(list(schema['fields'].keys())),
            [
                'author',
                'body',
                'id',
                'title',
            ]
        )
        self.assertEqual(schema['fields']['id']['type'], 'integer')
        self.assertEqual(schema['format'], 'application/json')

    def test_handle_not_implemented(self):
        self.res.request = FakeHttpRequest('TRACE')

        with self.assertRaises(MethodNotImplemented):
            self.res.handle('list')

    def test_handle_not_authenticated(self):
        # Special-cased above for testing.
        self.res.request = FakeHttpRequest('DELETE')

        with self.assertRaises(Unauthorized):
            self.res.handle('list')

        # Now with DEBUG off.
        settings.DEBUG = False
        self.addCleanup(setattr, settings, 'DEBUG', True)
        resp = self.res.handle('list')
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 401)
        self.assertEqual(json.loads(resp.content.decode('utf-8')), {
            'error': 'Unauthorized.',
        })

    def test_handle_build_err(self):
        # Special-cased above for testing.
        self.res.request = FakeHttpRequest('POST')
        settings.DEBUG = False
        self.addCleanup(setattr, settings, 'DEBUG', True)

        resp = self.res.handle('detail')
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 500)
        self.assertEqual(json.loads(resp.content.decode('utf-8')), {
            'error': 'This is a random & crazy exception.'
        })

    def test_build_url_name(self):
        self.assertEqual(
            DjTestResource.build_url_name('list'),
            'api_djtest_list'
        )
        self.assertEqual(
            DjTestResource.build_url_name('detail'),
            'api_djtest_detail'
        )
        self.assertEqual(
            DjTestResource.build_url_name('schema'),
            'api_djtest_schema'
        )

        self.assertEqual(
            DjTestResource.build_url_name('list', name_prefix='v2_'),
            'v2_list'
        )
        self.assertEqual(
            DjTestResource.build_url_name('detail', name_prefix='v2_'),
            'v2_detail'
        )
        self.assertEqual(
            DjTestResource.build_url_name('schema', name_prefix='v2_'),
            'v2_schema'
        )

    def test_urls(self):
        patterns = DjTestResource.urls()
        self.assertEqual(len(patterns), 2)
        self.assertEqual(patterns[0].name, 'api_djtest_list')
        self.assertEqual(patterns[1].name, 'api_djtest_detail')

        patterns = DjTestResource.urls(name_prefix='v2_tests')
        self.assertEqual(len(patterns), 2)
        self.assertEqual(patterns[0].name, 'v2_tests_list')
        self.assertEqual(patterns[1].name, 'v2_tests_detail')

    def test_create(self):
        self.res.request = FakeHttpRequest('POST', body='{"id": 6, "title": "Moved hosts", "author": "daniel"}')
        self.assertEqual(len(self.res.fake_db), 3)

        resp = self.res.handle('list')
        self.assertEqual(resp['Content-Type'], 'application/json')
        self.assertEqual(resp.status_code, 201)
        self.assertEqual(resp.content.decode('utf-8'), '')

        # Check the internal state.
        self.assertEqual(len(self.res.fake_db), 4)
        self.assertEqual(self.res.data, {
            'author': 'daniel',
            'id': 6,
            'title': 'Moved hosts'
        })
<|endoftext|>