<commit_before>import platform
import re
import os
import subprocess
import sys

from monitor import Monitor

class MonitorSvc(Monitor):
    """Monitor a service handled by daemontools."""

    type = "svc"
    path = ""

    def __init__(self, name, config_options):
        Monitor.__init__(self, name, config_options)
        try:
            self.path = config_options["path"]
        except:
            raise RuntimeError("Required configuration fields missing")
        self.params = ("svok %s" % self.path).split(" ")

    def run_test(self):
        if self.path == "":
            return
        try:
            result = subprocess.call(self.params)
            if result is None:
                result = 0
            if result > 0:
                self.record_fail("svok returned %d" % int(result))
                return False
            else:
                self.record_success()
                return True
        except Exception, e:
            self.record_fail("Exception while executing svok: %s" % e)
            return False

    def describe(self):
        return "Checking that the supervise-managed service in %s is running." % self.path

    def get_params(self):
        return (self.path, )

class MonitorService(Monitor):
    """Monitor a Windows service"""

    service_name = ""
    want_state = "RUNNING"
    host = "."
    type = "service"

    def __init__(self, name, config_options):
        Monitor.__init__(self, name, config_options)
        try:
            service_name = config_options["service"]
        except:
            raise RuntimeError("Required configuration fields missing")
        if 'state' in config_options:
            want_state = config_options["state"]
        else:
            want_state = "RUNNING"

        if 'host' in config_options:
            host = config_options["host"]
        else:
            host = "."

        if service_name == "":
            raise RuntimeError("missing service name")
        if want_state not in ["RUNNING", "STOPPED"]:
            raise RuntimeError("invalid state")

        self.service_name = service_name
        self.want_state = want_state
        self.host = host

    def run_test(self):
        """Check the service is in the desired state"""
        r = re.compile("STATE +: [0-9]+ +%s" % self.want_state)
        try:
            if platform.system() == "CYGWIN_NT-6.0":
                host = '\\\\\\\\' + self.host
            elif platform.system() in ["Microsoft", "Windows"]:
                host = '\\\\' + self.host
            else:
                # we need windows for sc
                self.record_fail("Cannot check for Windows services while running on a non-Windows platform.")
                return False

            output = str(subprocess.check_output(['sc', host, 'query', self.service_name]))
            matches = r.search(output)
            if matches:
                self.record_success()
                return True
        except Exception, e:
            sys.stderr.write("%s\n" % e)
            pass
        self.record_fail()
        return False

    def describe(self):
        """Explains what this instance is checking"""
        return "checking for service called %s in state %s" % (self.service_name, self.want_state)

    def get_params(self):
        return (self.host, self.service_name, self.want_state)

class MonitorRC(Monitor):
    """Monitor a service handled by an rc.d script.

    This monitor checks the return code of /usr/local/etc/rc.d/<name>
    and reports failure if it's non-zero by default.
    """

    type = "rc"

    def __init__(self, name, config_options):
        """Initialise the class.
        Change script path to /etc/rc.d/ to monitor base system services. If the
        script path ends with /, the service name is appended."""
        Monitor.__init__(self, name, config_options)
        try:
            service_name = config_options["service"]
        except:
            raise RuntimeError("Required configuration fields missing")
        if 'path' in config_options:
            script_path = config_options["path"]
        else:
            script_path = "/usr/local/etc/rc.d/"
        if 'return_code' in config_options:
            want_return_code = int(config_options["return_code"])
        else:
            want_return_code = 0

        if service_name == "":
            raise RuntimeError("missing service name")
        if script_path == "":
            raise RuntimeError("missing script path")
        if script_path.endswith("/"):
            script_path = script_path + service_name
        self.script_path = script_path
        self.service_name = service_name
        self.want_return_code = want_return_code
        # Check if we need a .sh (old-style RC scripts in FreeBSD)
        if not os.path.isfile(self.script_path):
            if os.path.isfile(self.script_path + ".sh"):
                self.script_path = self.script_path + ".sh"
            else:
                raise RuntimeError("Script %s(.sh) does not exist" % self.script_path)

    def run_test(self):
        """Check the service is in the desired state."""
        if platform.system() in ["Microsoft", "CYGWIN_NT-6.0"]:
            self.last_result = "Cannot run this monitor on a non-UNIX host."
            self.is_error = True
            return False
        try:
            returncode = subprocess.check_call([self.script_path, 'status'])
            if returncode == self.want_return_code:
                self.record_success()
                return True
        except subprocess.CalledProcessError, e:
            if e.returncode == self.want_return_code:
                self.record_success()
                return True
        except Exception, e:
            self.record_fail("Exception while executing script: %s" % e)
            return False
        self.record_fail("Return code: %d (wanted %d)" % (returncode, self.want_return_code))
        return False

    def get_params(self):
        return (self.service_name, self.want_return_code)

    def describe(self):
        """Explains what this instance is checking."""
        return "Checks service %s is running" % self.script_path

class MonitorEximQueue(Monitor):
    """Make sure an exim queue isn't too big."""

    type = "eximqueue"
    max_length = 10
    r = re.compile("(?P<count>\d+) matches out of (?P<total>\d+) messages")
    path = "/usr/local/sbin"

    def __init__(self, name, config_options):
        Monitor.__init__(self, name, config_options)
        try:
            self.max_length = int(config_options["max_length"])
        except:
            raise RuntimeError("Required configuration field 'max_length' missing or not an integer")
        if not (self.max_length > 0):
            raise RuntimeError("'max_length' must be >= 1")
        if "path" in config_options:
            self.path = config_options["path"]

    def run_test(self):
        try:
            output = subprocess.check_output([os.path.join(self.path, "exiqgrep"), "-xc"])
            for line in output:
                matches = self.r.match(line)
                if matches:
                    count = int(matches.group("count"))
                    # total = int(matches.group("total"))
                    if count > self.max_length:
                        if count == 1:
                            self.record_fail("%d message queued" % count)
                        else:
                            self.record_fail("%d messages queued" % count)
                        return False
                    else:
                        if count == 1:
                            self.record_success("%d message queued" % count)
                        else:
                            self.record_success("%d messages queued" % count)
                        return True
            self.record_fail("Error getting queue size")
            return False
        except Exception, e:
            self.record_fail("Error running exiqgrep: %s" % e)
            return False

    def describe(self):
        return "Checking the exim queue length is < %d" % self.max_length

    def get_params(self):
        return (self.max_length, )

class MonitorWindowsDHCPScope(Monitor):
    """Checks a Windows DHCP scope to make sure it has sufficient free IPs in the pool."""

    # netsh dhcp server \\SERVER scope SCOPE show clients
    # "No of Clients(version N): N in the Scope

    type = "dhcpscope"
    max_used = 0
    scope = ""
    server = ""
    r = re.compile("No of Clients\(version \d+\): (?P<clients>\d+) in the Scope")

    def __init__(self, name, config_options):
        if not self.is_windows(True):
            raise RuntimeError("DHCPScope monitor requires a Windows platform.")
        Monitor.__init__(self, name, config_options)
        try:
            self.max_used = int(config_options["max_used"])
        except:
            raise RuntimeError("Required configuration field 'max_used' missing or not an integer")
        if not (self.max_used > 0):
            raise RuntimeError("max_used must be >= 1")

        try:
            self.scope = config_options["scope"]
        except:
            raise RuntimeError("Required configuration field 'scope' missing")

    def run_test(self):
        try:
            output = str(subprocess.check_output(["netsh", "dhcp", "server", "scope", self.scope, "show", "clients"]))
            matches = self.r.search(line)
            if matches:
                clients = int(matches.group("clients"))
                if clients > self.max_used:
                    self.record_fail("%d clients in scope" % clients)
                    return False
                else:
                    self.record_success("%d clients in scope" % clients)
                    return True
            self.record_fail("Error getting client count: no match")
            return False
        except Exception, e:
            print e
            self.record_fail("Error getting client count: %s", e)
            return False

    def describe(self):
        return "Checking the DHCP scope has fewer than %d leases" % self.max_used
<commit_msg>Prevent rc monitor throwing exception on failure<commit_after>import platform
import re
import os
import subprocess
import sys

from monitor import Monitor

class MonitorSvc(Monitor):
    """Monitor a service handled by daemontools."""

    type = "svc"
    path = ""

    def __init__(self, name, config_options):
        Monitor.__init__(self, name, config_options)
        try:
            self.path = config_options["path"]
        except:
            raise RuntimeError("Required configuration fields missing")
        self.params = ("svok %s" % self.path).split(" ")

    def run_test(self):
        if self.path == "":
            return
        try:
            result = subprocess.call(self.params)
            if result is None:
                result = 0
            if result > 0:
                self.record_fail("svok returned %d" % int(result))
                return False
            else:
                self.record_success()
                return True
        except Exception, e:
            self.record_fail("Exception while executing svok: %s" % e)
            return False

    def describe(self):
        return "Checking that the supervise-managed service in %s is running." % self.path

    def get_params(self):
        return (self.path, )

class MonitorService(Monitor):
    """Monitor a Windows service"""

    service_name = ""
    want_state = "RUNNING"
    host = "."
    type = "service"

    def __init__(self, name, config_options):
        Monitor.__init__(self, name, config_options)
        try:
            service_name = config_options["service"]
        except:
            raise RuntimeError("Required configuration fields missing")
        if 'state' in config_options:
            want_state = config_options["state"]
        else:
            want_state = "RUNNING"

        if 'host' in config_options:
            host = config_options["host"]
        else:
            host = "."

        if service_name == "":
            raise RuntimeError("missing service name")
        if want_state not in ["RUNNING", "STOPPED"]:
            raise RuntimeError("invalid state")

        self.service_name = service_name
        self.want_state = want_state
        self.host = host

    def run_test(self):
        """Check the service is in the desired state"""
        r = re.compile("STATE +: [0-9]+ +%s" % self.want_state)
        try:
            if platform.system() == "CYGWIN_NT-6.0":
                host = '\\\\\\\\' + self.host
            elif platform.system() in ["Microsoft", "Windows"]:
                host = '\\\\' + self.host
            else:
                # we need windows for sc
                self.record_fail("Cannot check for Windows services while running on a non-Windows platform.")
                return False

            output = str(subprocess.check_output(['sc', host, 'query', self.service_name]))
            matches = r.search(output)
            if matches:
                self.record_success()
                return True
        except Exception, e:
            sys.stderr.write("%s\n" % e)
            pass
        self.record_fail()
        return False

    def describe(self):
        """Explains what this instance is checking"""
        return "checking for service called %s in state %s" % (self.service_name, self.want_state)

    def get_params(self):
        return (self.host, self.service_name, self.want_state)

class MonitorRC(Monitor):
    """Monitor a service handled by an rc.d script.

    This monitor checks the return code of /usr/local/etc/rc.d/<name>
    and reports failure if it's non-zero by default.
    """

    type = "rc"

    def __init__(self, name, config_options):
        """Initialise the class.
        Change script path to /etc/rc.d/ to monitor base system services. If the
        script path ends with /, the service name is appended."""
        Monitor.__init__(self, name, config_options)
        try:
            service_name = config_options["service"]
        except:
            raise RuntimeError("Required configuration fields missing")
        if 'path' in config_options:
            script_path = config_options["path"]
        else:
            script_path = "/usr/local/etc/rc.d/"
        if 'return_code' in config_options:
            want_return_code = int(config_options["return_code"])
        else:
            want_return_code = 0

        if service_name == "":
            raise RuntimeError("missing service name")
        if script_path == "":
            raise RuntimeError("missing script path")
        if script_path.endswith("/"):
            script_path = script_path + service_name
        self.script_path = script_path
        self.service_name = service_name
        self.want_return_code = want_return_code
        # Check if we need a .sh (old-style RC scripts in FreeBSD)
        if not os.path.isfile(self.script_path):
            if os.path.isfile(self.script_path + ".sh"):
                self.script_path = self.script_path + ".sh"
            else:
                raise RuntimeError("Script %s(.sh) does not exist" % self.script_path)

    def run_test(self):
        """Check the service is in the desired state."""
        if platform.system() in ["Microsoft", "CYGWIN_NT-6.0"]:
            self.last_result = "Cannot run this monitor on a non-UNIX host."
            self.is_error = True
            return False
        try:
            returncode = subprocess.check_call([self.script_path, 'status'])
            if returncode == self.want_return_code:
                self.record_success()
                return True
        except subprocess.CalledProcessError, e:
            if e.returncode == self.want_return_code:
                self.record_success()
                return True
            returncode = -1
        except Exception, e:
            self.record_fail("Exception while executing script: %s" % e)
            return False
        self.record_fail("Return code: %d (wanted %d)" % (returncode, self.want_return_code))
        return False

    def get_params(self):
        return (self.service_name, self.want_return_code)

    def describe(self):
        """Explains what this instance is checking."""
        return "Checks service %s is running" % self.script_path

class MonitorEximQueue(Monitor):
    """Make sure an exim queue isn't too big."""

    type = "eximqueue"
    max_length = 10
    r = re.compile("(?P<count>\d+) matches out of (?P<total>\d+) messages")
    path = "/usr/local/sbin"

    def __init__(self, name, config_options):
        Monitor.__init__(self, name, config_options)
        try:
            self.max_length = int(config_options["max_length"])
        except:
            raise RuntimeError("Required configuration field 'max_length' missing or not an integer")
        if not (self.max_length > 0):
            raise RuntimeError("'max_length' must be >= 1")
        if "path" in config_options:
            self.path = config_options["path"]

    def run_test(self):
        try:
            output = subprocess.check_output([os.path.join(self.path, "exiqgrep"), "-xc"])
            for line in output:
                matches = self.r.match(line)
                if matches:
                    count = int(matches.group("count"))
                    # total = int(matches.group("total"))
                    if count > self.max_length:
                        if count == 1:
                            self.record_fail("%d message queued" % count)
                        else:
                            self.record_fail("%d messages queued" % count)
                        return False
                    else:
                        if count == 1:
                            self.record_success("%d message queued" % count)
                        else:
                            self.record_success("%d messages queued" % count)
                        return True
            self.record_fail("Error getting queue size")
            return False
        except Exception, e:
            self.record_fail("Error running exiqgrep: %s" % e)
            return False

    def describe(self):
        return "Checking the exim queue length is < %d" % self.max_length

    def get_params(self):
        return (self.max_length, )

class MonitorWindowsDHCPScope(Monitor):
    """Checks a Windows DHCP scope to make sure it has sufficient free IPs in the pool."""

    # netsh dhcp server \\SERVER scope SCOPE show clients
    # "No of Clients(version N): N in the Scope

    type = "dhcpscope"
    max_used = 0
    scope = ""
    server = ""
    r = re.compile("No of Clients\(version \d+\): (?P<clients>\d+) in the Scope")

    def __init__(self, name, config_options):
        if not self.is_windows(True):
            raise RuntimeError("DHCPScope monitor requires a Windows platform.")
        Monitor.__init__(self, name, config_options)
        try:
            self.max_used = int(config_options["max_used"])
        except:
            raise RuntimeError("Required configuration field 'max_used' missing or not an integer")
        if not (self.max_used > 0):
            raise RuntimeError("max_used must be >= 1")

        try:
            self.scope = config_options["scope"]
        except:
            raise RuntimeError("Required configuration field 'scope' missing")

    def run_test(self):
        try:
            output = str(subprocess.check_output(["netsh", "dhcp", "server", "scope", self.scope, "show", "clients"]))
            matches = self.r.search(line)
            if matches:
                clients = int(matches.group("clients"))
                if clients > self.max_used:
                    self.record_fail("%d clients in scope" % clients)
                    return False
                else:
                    self.record_success("%d clients in scope" % clients)
                    return True
            self.record_fail("Error getting client count: no match")
            return False
        except Exception, e:
            print e
            self.record_fail("Error getting client count: %s", e)
            return False

    def describe(self):
        return "Checking the DHCP scope has fewer than %d leases" % self.max_used
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Created on Thu Jun 26 14:17:38 2014
updated 2015.01.27
@author: Kyle Ellefsen
"""
from __future__ import (absolute_import, division,print_function)
import dependency_check
from future.builtins import (bytes, dict, int, list, object, range, str, ascii, chr, hex, input, next, oct, pow, round, super, filter, map, zip)
import time
tic=time.time()
import os, sys
import numpy as np
from PyQt4.QtCore import * # Qt is Nokias GUI rendering code written in C++.  PyQt4 is a library in python which binds to Qt
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSignal as Signal
from pyqtgraph import plot, show
import pyqtgraph as pg
import global_vars as g
from window import Window
from roi import load_roi, makeROI
from CDF import *
from sklearn.cluster import DBSCAN

from histogram import Histogram
from process.motility_ import *
from process.file_ import *

try:
    os.chdir(os.path.split(os.path.realpath(__file__))[0])
except NameError:
    pass

class TrackPlot(pg.PlotDataItem):
    '''
    PlotDataItem representation of a set of tracks, imported from a bin file.
    Filterable by track length, mean lag distance, and neighbor points
    '''
    tracksChanged = Signal()
    def __init__(self, *args, **kargs):
        super(TrackPlot, self).__init__()
        self.all_tracks = []
        self.filtered_tracks = []
        self.waitForUpdate = False
        self.means = pg.ScatterPlotItem()
        self.means.setVisible(False)
        self.tracks = pg.PlotDataItem()
        self.tracks.setParentItem(self)
        self.means.setParentItem(self)

    def setTracks(self, track_list):
        self.all_tracks = track_list
        self.filter()

    def filter(self):
        if self.waitForUpdate or len(self.all_tracks) == 0:
            return
        self.filtered_tracks = []
        for tr in self.all_tracks:
            if isValidTrack(tr):
                self.filtered_tracks.append(tr)

        if g.m.additionalGroupBox.isChecked() and g.m.neighborsSpin.value() > 0:
            filter_ids = get_clusters(self.filtered_tracks)
            print([i for i in filter_ids])
            self.filtered_tracks = [self.filtered_tracks[i] for i, cluster in enumerate(filter_ids) if cluster >= 0]

        self._replot()
        self.tracksChanged.emit()

    def _replot(self):
        tracks_x = []
        tracks_y = []
        mean_x = []
        mean_y = []
        connect_list = []
        for tr in self.filtered_tracks:
            tracks_x.extend(tr['x_cor'])
            tracks_y.extend(tr['y_cor'])
            mean_x.append(tr['mean_x'])
            mean_y.append(tr['mean_y'])
            connect_list.extend([1] * (len(tr['x_cor']) - 1) + [0])
        if g.m.autoFocusCheck.isChecked() and len(tracks_x) > 0 and len(tracks_y) > 0:
            g.m.trackView.imageview.view.setRange(xRange=(min(tracks_x), max(tracks_x)), yRange=(min(tracks_y), max(tracks_y)))
        self.tracks.setData(x=tracks_x, y=tracks_y, connect=np.array(connect_list))
        self.means.setData(x=mean_x, y=mean_y, symbol='x', brush=(255, 0, 0), pen=(255, 0, 0))

    def export(self, filename, filtered=False):
        tracks = self.all_tracks if not filtered else self.filtered_tracks
        g.m.statusBar().showMessage('Saving tracks to {}'.format(os.path.basename(filename)))
        t = time.time()
        with open(filename, 'w') as outf:
            for tr in tracks:
                outf.write('\n'.join(         ['{0:.4f}\t{1:.4f}\t{2:.4f}'.format(t,x,y) for t,x,y in zip(tr['frames'], tr['x_cor'], tr['y_cor'])]       ))
                outf.write('\n')
            outf.write('\n')

        g.m.statusBar().showMessage('Successfully saved tracks in {}'.format(time.time() - t))
    def export_gui(self):
        filename=g.m.filename
        try:
            directory=os.path.dirname(filename)
        except:
            directory = ''
        prompt = 'Export Plotted Tracks'
        filetypes='*.txt'
        if filename is not None and directory != '':
            filename= QFileDialog.getSaveFileName(g.m, prompt, directory, filetypes)
        else:
            filename= QFileDialog.getSaveFileName(g.m, prompt, filetypes)
        filename=str(filename)
        if filename != '':
            self.export(filename,filtered=True)
            g.m.filename = filename
        else:
            g.m.statusBar().showMessage('Save Cancelled')

def isValidTrack(track):
    if not g.m.MSLDGroupBox.isChecked() or g.m.MSLDMinSpin.value() <= track['mean_dis_pixel_lag'] <= g.m.MSLDMaxSpin.value():
        if g.m.minLengthSpin.value() <= track['fr_length'] <= g.m.maxLengthSpin.value():
            if not g.m.ignoreOutsideCheck.isChecked() or track_in_roi(track):
                return True
    return False

def export_real_distances(filename):

    coords = g.m.trackView.imported.getData()
    means = g.m.trackPlot.means.getData()
    if np.size(coords) == 0 or np.size(means) == 0:
        print("Must have track means and imported coordinates to export distances between them")
    else:
        export_distances(filename, means, coords)

def import_mat(mat):
    if len(mat) == 0:
        return
    g.mat = mat
    main, reject, r = create_main_data_struct(mat, g.m.MSLDMinSpin.value(), g.m.MSLDMaxSpin.value())
    g.m.trackPlot.waitForUpdate = True
    g.m.minLengthSpin.setValue(4)
    g.m.maxLengthSpin.setValue(20)
    g.m.MSLDMinSpin.setValue(0)
    g.m.MSLDMaxSpin.setValue(round(max([tr['mean_dis_pixel_lag'] for tr in main])))
    g.m.neighborDistanceSpin.setValue(round(max([max(track['dis_pixel_lag']) for track in main])))
    g.m.trackPlot.waitForUpdate = False

    g.m.trackPlot.setTracks(main)

def get_clusters(tracks):
    neighbors = g.m.neighborsSpin.value()
    dist = g.m.neighborDistanceSpin.value()
    data = np.array([[tr['mean_x'], tr['mean_y']] for tr in tracks])
    scanner = DBSCAN(eps=dist, min_samples=neighbors)
    ids = scanner.fit_predict(data)
    return ids

def track_in_roi(track):
    for roi in g.m.currentWindow.rois:
        if roi.contains(track['mean_x'], track['mean_y']):
            return True
    return False

def updateMSD(tracks):
    x, y, er = calculate_MSD_plot(tracks, [g.m.minLengthSpin.value(), g.m.maxLengthSpin.value()])
    g.m.MSDWidget.clear()
    err = pg.ErrorBarItem(x=x, y=y, top=er, bottom=er, beam=0.5)
    g.m.MSDWidget.plot_data = {'er': er, 'x': x, 'y': y}
    g.m.MSDWidget.addItem(err)
    msd = pg.PlotDataItem(x = x, y = y, pen = (0, 255, 0))
    g.m.MSDWidget.addItem(msd)

def updateHistogram(tracks):
    mean_dists = np.array([tr['mean_dis_pixel_lag'] for tr in tracks])
    g.m.histogram.setData(mean_dists)

def update_plots():
    tracks = g.m.trackPlot.filtered_tracks
    updateHistogram(tracks)
    updateMSD(tracks)
    g.m.CDFWidget.setTracks(tracks)
    # update MSD, histogram, and CDF? with new filtered tracks

def initializeMainGui():
    g.init('gui/MotilityTracking.ui')
    g.m.trackView = Window(np.zeros((3, 3, 3)))
    g.m.histogram = Histogram(title='Mean Single Lag Distance Histogram', labels={'left': 'Count', 'bottom': 'Mean SLD Per Track (Pixels)'})
    g.m.trackPlot = TrackPlot()
    g.m.trackPlot.tracksChanged.connect(update_plots)
    g.m.trackView.imageview.addItem(g.m.trackPlot)
    g.m.trackView.imported = pg.ScatterPlotItem()
    g.m.trackView.imageview.addItem(g.m.trackView.imported)

    g.m.actionImportBin.triggered.connect(lambda : open_file_gui(lambda f: import_mat(open_bin(f)),  prompt='Import .bin file of tracks', filetypes='*.bin'))
    g.m.actionImportBackground.triggered.connect(lambda : open_file_gui(set_background_image,  prompt='Select tif file as background image', filetypes='*.tif *.tiff *.stk'))
    g.m.actionImportCoordinates.triggered.connect(lambda : open_file_gui(import_coords, prompt='Import coordinates from txt file', filetypes='*.txt'))
    g.m.actionSimulateDistances.triggered.connect(lambda : save_file_gui(simulate_distances, prompt = 'Save simulated distances', filetypes='*.txt'))
    g.m.actionExportMSD.triggered.connect(lambda : save_file_gui(exportMSD, prompt='Export Mean Squared Displacement Values', filetypes='*.txt'))
    g.m.actionExportHistogram.triggered.connect(lambda : save_file_gui(g.m.histogram.export, prompt='Export Histogram Values', filetypes='*.txt'))
    g.m.actionExportTrackLengths.triggered.connect(lambda : save_file_gui(export_track_lengths, prompt='Export Track Lengths', filetypes='*.txt'))
    g.m.actionExportOutlined.triggered.connect(g.m.trackPlot.export_gui)
    g.m.actionExportDistances.triggered.connect(lambda : save_file_gui(export_real_distances,  prompt='Export Distances', filetypes='*.txt'))

    g.m.MSLDMinSpin.setOpts(value=0, decimals=2, maximum=1000)
    g.m.MSLDMaxSpin.setOpts(value=100, decimals=2, maximum=1000)
    g.m.neighborsSpin.setOpts(value=0, maximum=100, int=True, step=1)
    g.m.neighborDistanceSpin.setOpts(value=1, decimals=2, maximum=100)
    g.m.minLengthSpin.setOpts(value=4, maximum=1000, int=True, step=1)
    g.m.maxLengthSpin.setOpts(value=20, maximum=1000, int=True, step=1)

    g.m.MSLDGroupBox.toggled.connect(g.m.trackPlot.filter)
    g.m.additionalGroupBox.toggled.connect(g.m.trackPlot.filter)
    g.m.MSLDMaxSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.MSLDMinSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.neighborDistanceSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.neighborsSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.minLengthSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.maxLengthSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.hideBackgroundCheck.toggled.connect(lambda v: g.m.trackView.imageview.getImageItem().setVisible(not v))
    g.m.ignoreOutsideCheck.toggled.connect(g.m.trackPlot.filter)
    g.m.plotMeansCheck.toggled.connect(g.m.trackPlot.means.setVisible)
    g.m.plotTracksCheck.toggled.connect(g.m.trackPlot.tracks.setVisible)

    g.m.viewTab.layout().insertWidget(0, g.m.trackView)

    g.m.MSDWidget = pg.PlotWidget(title='Mean Squared Displacement Per Lag', labels={'left': 'Mean Squared Disance (p^2)', 'bottom': 'Lag Count'})
    g.m.analysisTab.layout().addWidget(g.m.MSDWidget)

    g.m.analysisTab.layout().addWidget(g.m.histogram)

    g.m.CDFWidget = CDFWidget()#pg.PlotWidget(title = 'Cumulative Distribution Function', labels={'left': 'Cumulative Probability', 'bottom': 'Single Lag Displacement Squared'})
    #g.m.CDFPlot = pg.PlotCurveItem()
    g.m.cdfTab.layout().addWidget(g.m.CDFWidget)

    g.m.installEventFilter(mainWindowEventEater)
    g.m.setWindowTitle('Motility Tracking')
    g.m.show()

class MainWindowEventEater(QObject):
    def __init__(self,parent=None):
        QObject.__init__(self,parent)
    def eventFilter(self,obj,event):
        if (event.type()==QEvent.DragEnter):
            if event.mimeData().hasUrls():
                event.accept()   # must accept the dragEnterEvent or else the dropEvent can't occur !!!
            else:
                event.ignore()
        if (event.type() == QEvent.Drop):
            if event.mimeData().hasUrls():   # if file or link is dropped
                url = event.mimeData().urls()[0]   # get first url
                filename=url.toString()
                filename=filename.split('file:///')[1]
                print('filename={}'.format(filename))
                g.m.filename=filename
                import_mat(bin2mat(filename))  #This fails on windows symbolic links.  http://stackoverflow.com/questions/15258506/os-path-islink-on-windows-with-python
                g.m.setWindowTitle('Motility Tracking - ' + filename)
                event.accept()
            else:
                event.ignore()
        return False # lets the event continue to the edit
mainWindowEventEater = MainWindowEventEater()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    initializeMainGui()

    insideSpyder='SPYDER_SHELL_ID' in os.environ
    if not insideSpyder: #if we are running outside of Spyder
        sys.exit(app.exec_()) #This is required to run outside of Spyder

<commit_msg>fixed compatility with pyqtgraph 0.10.0<commit_after># -*- coding: utf-8 -*-
"""
Created on Thu Jun 26 14:17:38 2014
updated 2015.01.27
@author: Kyle Ellefsen
"""
from __future__ import (absolute_import, division,print_function)
import dependency_check
from future.builtins import (bytes, dict, int, list, object, range, str, ascii, chr, hex, input, next, oct, pow, round, super, filter, map, zip)
import time
tic=time.time()
import os, sys
import numpy as np
from PyQt4.QtCore import * # Qt is Nokias GUI rendering code written in C++.  PyQt4 is a library in python which binds to Qt
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSignal as Signal
from pyqtgraph import plot, show
import pyqtgraph as pg
import global_vars as g
from window import Window
from roi import load_roi, makeROI
from CDF import *
from sklearn.cluster import DBSCAN

from histogram import Histogram
from process.motility_ import *
from process.file_ import *

try:
    os.chdir(os.path.split(os.path.realpath(__file__))[0])
except NameError:
    pass

class TrackPlot(pg.PlotDataItem):
    '''
    PlotDataItem representation of a set of tracks, imported from a bin file.
    Filterable by track length, mean lag distance, and neighbor points
    '''
    tracksChanged = Signal()
    def __init__(self, *args, **kargs):
        super(TrackPlot, self).__init__()
        self.all_tracks = []
        self.filtered_tracks = []
        self.waitForUpdate = False
        self.means = pg.ScatterPlotItem()
        self.means.setVisible(False)
        self.tracks = pg.PlotDataItem()
        self.tracks.setParentItem(self)
        self.means.setParentItem(self)

    def setTracks(self, track_list):
        self.all_tracks = track_list
        self.filter()

    def filter(self):
        if self.waitForUpdate or len(self.all_tracks) == 0:
            return
        self.filtered_tracks = []
        for tr in self.all_tracks:
            if isValidTrack(tr):
                self.filtered_tracks.append(tr)

        if g.m.additionalGroupBox.isChecked() and g.m.neighborsSpin.value() > 0:
            filter_ids = get_clusters(self.filtered_tracks)
            print([i for i in filter_ids])
            self.filtered_tracks = [self.filtered_tracks[i] for i, cluster in enumerate(filter_ids) if cluster >= 0]

        self._replot()
        self.tracksChanged.emit()

    def _replot(self):
        tracks_x = []
        tracks_y = []
        mean_x = []
        mean_y = []
        connect_list = []
        for tr in self.filtered_tracks:
            tracks_x.extend(tr['x_cor'])
            tracks_y.extend(tr['y_cor'])
            mean_x.append(tr['mean_x'])
            mean_y.append(tr['mean_y'])
            connect_list.extend([1] * (len(tr['x_cor']) - 1) + [0])
        if g.m.autoFocusCheck.isChecked() and len(tracks_x) > 0 and len(tracks_y) > 0:
            g.m.trackView.imageview.view.setRange(xRange=(min(tracks_x), max(tracks_x)), yRange=(min(tracks_y), max(tracks_y)))
        self.tracks.setData(x=tracks_x, y=tracks_y, connect=np.array(connect_list))
        self.means.setData(x=mean_x, y=mean_y, symbol='x', brush=(255, 0, 0), pen=(255, 0, 0))

    def export(self, filename, filtered=False):
        tracks = self.all_tracks if not filtered else self.filtered_tracks
        g.m.statusBar().showMessage('Saving tracks to {}'.format(os.path.basename(filename)))
        t = time.time()
        with open(filename, 'w') as outf:
            for tr in tracks:
                outf.write('\n'.join(         ['{0:.4f}\t{1:.4f}\t{2:.4f}'.format(t,x,y) for t,x,y in zip(tr['frames'], tr['x_cor'], tr['y_cor'])]       ))
                outf.write('\n')
            outf.write('\n')

        g.m.statusBar().showMessage('Successfully saved tracks in {}'.format(time.time() - t))
    def export_gui(self):
        filename=g.m.filename
        try:
            directory=os.path.dirname(filename)
        except:
            directory = ''
        prompt = 'Export Plotted Tracks'
        filetypes='*.txt'
        if filename is not None and directory != '':
            filename= QFileDialog.getSaveFileName(g.m, prompt, directory, filetypes)
        else:
            filename= QFileDialog.getSaveFileName(g.m, prompt, filetypes)
        filename=str(filename)
        if filename != '':
            self.export(filename,filtered=True)
            g.m.filename = filename
        else:
            g.m.statusBar().showMessage('Save Cancelled')

def isValidTrack(track):
    if not g.m.MSLDGroupBox.isChecked() or g.m.MSLDMinSpin.value() <= track['mean_dis_pixel_lag'] <= g.m.MSLDMaxSpin.value():
        if g.m.minLengthSpin.value() <= track['fr_length'] <= g.m.maxLengthSpin.value():
            if not g.m.ignoreOutsideCheck.isChecked() or track_in_roi(track):
                return True
    return False

def export_real_distances(filename):

    coords = g.m.trackView.imported.getData()
    means = g.m.trackPlot.means.getData()
    if np.size(coords) == 0 or np.size(means) == 0:
        print("Must have track means and imported coordinates to export distances between them")
    else:
        export_distances(filename, means, coords)

def import_mat(mat):
    if len(mat) == 0:
        return
    g.mat = mat
    main, reject, r = create_main_data_struct(mat, g.m.MSLDMinSpin.value(), g.m.MSLDMaxSpin.value())
    g.m.trackPlot.waitForUpdate = True
    g.m.minLengthSpin.setValue(4)
    g.m.maxLengthSpin.setValue(20)
    g.m.MSLDMinSpin.setValue(0)
    g.m.MSLDMaxSpin.setValue(round(max([tr['mean_dis_pixel_lag'] for tr in main])))
    g.m.neighborDistanceSpin.setValue(round(max([max(track['dis_pixel_lag']) for track in main])))
    g.m.trackPlot.waitForUpdate = False

    g.m.trackPlot.setTracks(main)

def get_clusters(tracks):
    neighbors = g.m.neighborsSpin.value()
    dist = g.m.neighborDistanceSpin.value()
    data = np.array([[tr['mean_x'], tr['mean_y']] for tr in tracks])
    scanner = DBSCAN(eps=dist, min_samples=neighbors)
    ids = scanner.fit_predict(data)
    return ids

def track_in_roi(track):
    for roi in g.m.currentWindow.rois:
        if roi.contains(track['mean_x'], track['mean_y']):
            return True
    return False

def updateMSD(tracks):
    x, y, er = calculate_MSD_plot(tracks, [g.m.minLengthSpin.value(), g.m.maxLengthSpin.value()])
    g.m.MSDWidget.clear()
    err = pg.ErrorBarItem(x=x, y=y, top=er, bottom=er, beam=0.5)
    g.m.MSDWidget.plot_data = {'er': er, 'x': x, 'y': y}
    g.m.MSDWidget.addItem(err)
    msd = pg.PlotDataItem(x = x, y = y, pen = (0, 255, 0))
    g.m.MSDWidget.addItem(msd)

def updateHistogram(tracks):
    mean_dists = np.array([tr['mean_dis_pixel_lag'] for tr in tracks])
    g.m.histogram.setData(mean_dists)

def update_plots():
    tracks = g.m.trackPlot.filtered_tracks
    updateHistogram(tracks)
    updateMSD(tracks)
    g.m.CDFWidget.setTracks(tracks)
    # update MSD, histogram, and CDF? with new filtered tracks

def initializeMainGui():
    g.init('gui/MotilityTracking.ui')
    g.m.trackView = Window(np.zeros((3, 3, 3)))
    g.m.histogram = Histogram(title='Mean Single Lag Distance Histogram', labels={'left': 'Count', 'bottom': 'Mean SLD Per Track (Pixels)'})
    g.m.trackPlot = TrackPlot()
    g.m.trackPlot.tracksChanged.connect(update_plots)
    g.m.trackView.imageview.addItem(g.m.trackPlot)
    g.m.trackView.imported = pg.ScatterPlotItem()
    g.m.trackView.imageview.addItem(g.m.trackView.imported)

    g.m.actionImportBin.triggered.connect(lambda : open_file_gui(lambda f: import_mat(open_bin(f)),  prompt='Import .bin file of tracks', filetypes='*.bin'))
    g.m.actionImportBackground.triggered.connect(lambda : open_file_gui(set_background_image,  prompt='Select tif file as background image', filetypes='*.tif *.tiff *.stk'))
    g.m.actionImportCoordinates.triggered.connect(lambda : open_file_gui(import_coords, prompt='Import coordinates from txt file', filetypes='*.txt'))
    g.m.actionSimulateDistances.triggered.connect(lambda : save_file_gui(simulate_distances, prompt = 'Save simulated distances', filetypes='*.txt'))
    g.m.actionExportMSD.triggered.connect(lambda : save_file_gui(exportMSD, prompt='Export Mean Squared Displacement Values', filetypes='*.txt'))
    g.m.actionExportHistogram.triggered.connect(lambda : save_file_gui(g.m.histogram.export, prompt='Export Histogram Values', filetypes='*.txt'))
    g.m.actionExportTrackLengths.triggered.connect(lambda : save_file_gui(export_track_lengths, prompt='Export Track Lengths', filetypes='*.txt'))
    g.m.actionExportOutlined.triggered.connect(g.m.trackPlot.export_gui)
    g.m.actionExportDistances.triggered.connect(lambda : save_file_gui(export_real_distances,  prompt='Export Distances', filetypes='*.txt'))

    g.m.MSLDMinSpin.setOpts(value=0, decimals=2, bounds=(0, 100))
    g.m.MSLDMaxSpin.setOpts(value=100, decimals=2, bounds=(0, 100))
    g.m.neighborsSpin.setOpts(value=0, bounds=(0, 100), int=True, step=1)
    g.m.neighborDistanceSpin.setOpts(value=1, decimals=2, bounds=(0, 100))
    g.m.minLengthSpin.setOpts(value=4, bounds=(0, 1000), int=True, step=1)
    g.m.maxLengthSpin.setOpts(value=20, bounds=(0, 1000), int=True, step=1)

    g.m.MSLDGroupBox.toggled.connect(g.m.trackPlot.filter)
    g.m.additionalGroupBox.toggled.connect(g.m.trackPlot.filter)
    g.m.MSLDMaxSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.MSLDMinSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.neighborDistanceSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.neighborsSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.minLengthSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.maxLengthSpin.sigValueChanged.connect(g.m.trackPlot.filter)
    g.m.hideBackgroundCheck.toggled.connect(lambda v: g.m.trackView.imageview.getImageItem().setVisible(not v))
    g.m.ignoreOutsideCheck.toggled.connect(g.m.trackPlot.filter)
    g.m.plotMeansCheck.toggled.connect(g.m.trackPlot.means.setVisible)
    g.m.plotTracksCheck.toggled.connect(g.m.trackPlot.tracks.setVisible)

    g.m.viewTab.layout().insertWidget(0, g.m.trackView)

    g.m.MSDWidget = pg.PlotWidget(title='Mean Squared Displacement Per Lag', labels={'left': 'Mean Squared Disance (p^2)', 'bottom': 'Lag Count'})
    g.m.analysisTab.layout().addWidget(g.m.MSDWidget)

    g.m.analysisTab.layout().addWidget(g.m.histogram)

    g.m.CDFWidget = CDFWidget()#pg.PlotWidget(title = 'Cumulative Distribution Function', labels={'left': 'Cumulative Probability', 'bottom': 'Single Lag Displacement Squared'})
    #g.m.CDFPlot = pg.PlotCurveItem()
    g.m.cdfTab.layout().addWidget(g.m.CDFWidget)

    g.m.installEventFilter(mainWindowEventEater)
    g.m.setWindowTitle('Motility Tracking')
    g.m.show()

class MainWindowEventEater(QObject):
    def __init__(self,parent=None):
        QObject.__init__(self,parent)
    def eventFilter(self,obj,event):
        if (event.type()==QEvent.DragEnter):
            if event.mimeData().hasUrls():
                event.accept()   # must accept the dragEnterEvent or else the dropEvent can't occur !!!
            else:
                event.ignore()
        if (event.type() == QEvent.Drop):
            if event.mimeData().hasUrls():   # if file or link is dropped
                url = event.mimeData().urls()[0]   # get first url
                filename=url.toString()
                filename=filename.split('file:///')[1]
                print('filename={}'.format(filename))
                g.m.filename=filename
                import_mat(bin2mat(filename))  #This fails on windows symbolic links.  http://stackoverflow.com/questions/15258506/os-path-islink-on-windows-with-python
                g.m.setWindowTitle('Motility Tracking - ' + filename)
                event.accept()
            else:
                event.ignore()
        return False # lets the event continue to the edit
mainWindowEventEater = MainWindowEventEater()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    initializeMainGui()

    insideSpyder='SPYDER_SHELL_ID' in os.environ
    if not insideSpyder: #if we are running outside of Spyder
        sys.exit(app.exec_()) #This is required to run outside of Spyder

<|endoftext|>


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

import sys
import os.path
import codecs
import dfstrings
import time
import optparse

def make_js_from_po(path):
    strings = []
    for po in [p for p in dfstrings.get_po_strings(path) if "scope" in p and "dragonfly" in p["scope"] ]:
        strings.append(u"""ui_strings.%s="%s";""" % (po["jsname"], po["msgstr"]))
    return """/* Generated from %s at %s */
window.ui_strings || ( window.ui_strings  = {} )
window.ui_strings.lang_code = "%s";
%s""" % (unicode(os.path.basename(path)),
        unicode(time.asctime()),
        unicode(os.path.splitext(os.path.basename(path))[0]),
        u"\n".join(strings))

def _process_file(inpath, outfd):
    lines = [p["msgstr"] for p in dfstrings.get_po_strings(inpath)
        if "scope" in p and "dragonfly" in p["scope"] ]

    bad_escaped = dfstrings.get_strings_with_bad_escaping(lines)
    if bad_escaped:
        print "error: %s contains strings with bad escaping: %s" % (inpath, bad_escaped)
        return 1

    bad_format = dfstrings.get_strings_with_bad_format(lines)
    if bad_format:
        print "error: %s contains strings with bad formatting: %s" % (inpath, bad_format)
        return 1

    data = make_js_from_po(inpath)
    print "WRITING TO", outfd
    outfd.write(data)

def _process_dir(dirpath, destpath):
    files = _find_pofiles(dirpath)
    for path in files:
        out = os.path.join(destpath, os.path.basename(path))
        outfd = codecs.open(out, "w", encoding="utf_8_sig")
        process_file(path, outfd)
        outfd.close()

def _find_pofiles(top):
    """Make a list of all po files in dirctory top, or any subdir"""
    matches = []
    for dirpath, dirnames, filenames in os.walk(top):
        # only add files that are 5 chars long (<countrycode>.po)
        # and that ends in .po
        # and that does not already exist in the matches list
        # Search is top down, so most shallow match will remain
        matches.extend([os.path.join(dirpath, e)
                        for e in filenames
                        if len(e) == 5
                        and e.endswith(".po")
                        and e not in [os.path.basename(x) for x in matches]])
    return matches

def _parse_options():
    usage = """%prog [options] input [output]"""

    parser = optparse.OptionParser(usage)
    parser.add_option("-d", "--directory", dest="directory",
                      default=False, action="store_true",
                      help="Operate on directories rather than single files")

    options, args = parser.parse_args()

    if len(args) == 0:
        parser.error("Not enough arguments")

    if options.directory and len(args) != 2:
        parser.error("Need both source and target directory")

    return options, args

def main():
    options, args = _parse_options()

    if options.directory:
        _process_dir(args[0], args[1])
    else:
        outfd = sys.stdout
        if len(args) > 1:
            outfd = codecs.open(sys.argv[1], "w", encoding="utf_8_sig")

        _process_file(args[0], outfd)

        if not outfd is sys.stdout:
            outfd.close()

    return 0

if __name__ == "__main__":
    sys.exit(main())

<commit_msg>Fixed a typo and made the js file names match the format used in the src dir<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import os.path
import codecs
import dfstrings
import time
import optparse

def make_js_from_po(path):
    strings = []
    for po in [p for p in dfstrings.get_po_strings(path) if "scope" in p and "dragonfly" in p["scope"] ]:
        strings.append(u"""ui_strings.%s="%s";""" % (po["jsname"], po["msgstr"]))
    return """/* Generated from %s at %s */
window.ui_strings || ( window.ui_strings  = {} )
window.ui_strings.lang_code = "%s";
%s""" % (unicode(os.path.basename(path)),
        unicode(time.asctime()),
        unicode(os.path.splitext(os.path.basename(path))[0]),
        u"\n".join(strings))

def _process_file(inpath, outfd):
    lines = [p["msgstr"] for p in dfstrings.get_po_strings(inpath)
        if "scope" in p and "dragonfly" in p["scope"] ]

    bad_escaped = dfstrings.get_strings_with_bad_escaping(lines)
    if bad_escaped:
        print "error: %s contains strings with bad escaping: %s" % (inpath, bad_escaped)
        return 1

    bad_format = dfstrings.get_strings_with_bad_format(lines)
    if bad_format:
        print "error: %s contains strings with bad formatting: %s" % (inpath, bad_format)
        return 1

    data = make_js_from_po(inpath)
    print "WRITING TO", outfd
    outfd.write(data)

def _process_dir(dirpath, destpath):
    files = _find_pofiles(dirpath)
    for path in files:
        out = os.path.join(destpath, "ui_strings-%s.js" % os.path.basename(path)[:-3])
        outfd = codecs.open(out, "w", encoding="utf_8_sig")
        _process_file(path, outfd)
        outfd.close()

def _find_pofiles(top):
    """Make a list of all po files in dirctory top, or any subdir"""
    matches = []
    for dirpath, dirnames, filenames in os.walk(top):
        # only add files that are 5 chars long (<countrycode>.po)
        # and that ends in .po
        # and that does not already exist in the matches list
        # Search is top down, so most shallow match will remain
        matches.extend([os.path.join(dirpath, e)
                        for e in filenames
                        if len(e) == 5
                        and e.endswith(".po")
                        and e not in [os.path.basename(x) for x in matches]])
    return matches

def _parse_options():
    usage = """%prog [options] input [output]"""

    parser = optparse.OptionParser(usage)
    parser.add_option("-d", "--directory", dest="directory",
                      default=False, action="store_true",
                      help="Operate on directories rather than single files")

    options, args = parser.parse_args()

    if len(args) == 0:
        parser.error("Not enough arguments")

    if options.directory and len(args) != 2:
        parser.error("Need both source and target directory")

    return options, args

def main():
    options, args = _parse_options()

    if options.directory:
        _process_dir(args[0], args[1])
    else:
        outfd = sys.stdout
        if len(args) > 1:
            outfd = codecs.open(sys.argv[1], "w", encoding="utf_8_sig")

        _process_file(args[0], outfd)

        if not outfd is sys.stdout:
            outfd.close()

    return 0

if __name__ == "__main__":
    sys.exit(main())

<|endoftext|>


<commit_before>import json

from werkzeug.exceptions import HTTPException

import meerkat_api
from meerkat_api.resources.devices import DeviceResourceBase
from meerkat_api.test import db_util, settings

class TestDeviceResourceBase(meerkat_api.test.TestCase):
    def setUp(self):
        self.object_under_test = DeviceResourceBase()

    def test_get_sql_alchemy_filters_handles_bad_filters(self):
        bad_format_filter = "not:three_args"
        with self.assertRaises(HTTPException) as http_error:
            self.object_under_test.get_sql_alchemy_filters([bad_format_filter])
        http_exception = http_error.exception
        self.assertEqual(http_exception.code, 404)
        self.assertEqual(http_exception.data['message'], "Incorrect filter: {}".format(bad_format_filter))

    def test_get_sql_alchemy_filters_handles_non_existing_parameters(self):
        bad_argument_filter = "invalidParam:eq:foobar"
        with self.assertRaises(AttributeError) as attribute_error:
            self.object_under_test.get_sql_alchemy_filters([bad_argument_filter])
        the_exception = attribute_error.exception
        actual_argument_name = bad_argument_filter.split(':')[0]
        expected_error_message = "type object 'Data' has no attribute '{}'".format(actual_argument_name)
        self.assertEqual(the_exception.args[0], expected_error_message)

    def test_get_sql_alchemy_filters_handles_non_existing_comparators(self):
        bad_comparator_filter = "id:what?!$%#:NVM"
        with self.assertRaises(NotImplementedError):
            self.object_under_test.get_sql_alchemy_filters([bad_comparator_filter])

    def test_get_sql_alchemy_filters_return_valid_object(self):
        filters = ["id:eq:1", "date:gt:2017-01-01"]
        actual_sql_alchemy_filters = self.object_under_test.get_sql_alchemy_filters(filters)
        _comparator_to_str = {
            "eq": "=",
            "gt": ">"
        }
        for _filter, _actual_sql_filter in zip(filters, actual_sql_alchemy_filters):
            expected_left, expected_comparator, expected_right = _filter.split(":")
            expected = {
                "left": 'data.' + expected_left,
                "comparator": _comparator_to_str[expected_comparator],
                "right": expected_right
            }
            actual = {
                "left": str(_actual_sql_filter.left),
                "comparator": str(_actual_sql_filter).split()[1],
                "right": _actual_sql_filter.right.effective_value
            }

            for key in expected.keys():
                self.assertEqual(expected[key], actual[key])

    def test_get_variable_count_for_device_id(self):
        db_util.insert_cases(self.db_session, "public_health_report")
        device_id = "1"
        variable_id = "gen_1"
        actual = DeviceResourceBase._get_variable_count_for_deivce_id(device_id, variable_id, [])
        expected = {'deviceId': device_id, 'variable': variable_id, 'submissionsCount': 3}
        self.assertEqual(expected, actual)

    def test_get_variable_count_for_deivce_id_should_return_zero_for_no_data(self):
        db_util.insert_cases(self.db_session, "public_health_report")
        device_id = "4"
        variable_id = "gen_1"
        actual = DeviceResourceBase._get_variable_count_for_deivce_id(device_id, variable_id, [])
        expected = {'deviceId': device_id, 'variable': variable_id, 'submissionsCount': 0}
        self.assertEqual(expected, actual)

class TestDeviceSubmissions(meerkat_api.test.TestCase):
    def setUp(self):
        db_util.insert_cases(self.db_session, "public_health_report")

    def test_existing_device_id_with_submissions(self):
        device_id = '1'
        variable_id = 'tot_1'
        expected_submissions = 4

        actual = self.__get_actual_api_response(device_id, variable_id)
        expected = self.__get_expected_dict_response(device_id, expected_submissions, variable_id)

        self.assertDictEqual(expected, actual)

    def test_existing_device_id_with_no_submissions(self):
        device_id = '1'
        variable_id = 'fake_var_id'
        expected_submissions = 0

        actual = self.__get_actual_api_response(device_id, variable_id)
        expected = self.__get_expected_dict_response(device_id, expected_submissions, variable_id)

        self.assertDictEqual(expected, actual)

    def test_non_existing_device_id(self):
        device_id = '99999000000000000000001'
        variable_id = 'tot_1'
        expected_submissions = 0

        actual = self.__get_actual_api_response(device_id, variable_id)
        expected = self.__get_expected_dict_response(device_id, expected_submissions, variable_id)

        self.assertDictEqual(expected, actual)

    def __get_expected_dict_response(self, device_id, expected_submissions, variable_id):
        expected = {'deviceId': device_id, 'variable': variable_id, 'submissionsCount': expected_submissions}
        return expected

    def __get_actual_api_response(self, device_id, variable_id):
        endpoint_under_test = '/device/{}/submissions/{}'.format(device_id, variable_id)
        rv = self.app.get(endpoint_under_test, headers=settings.header)
        self.assertEqual(rv.status_code, 200)
        actual = json.loads(rv.data.decode("utf-8"))
        return actual

class TestDeviceSubmissionsForLocation(meerkat_api.test.TestCase):
    def setUp(self):
        db_util.insert_cases(self.db_session, "public_health_report")
        db_util.insert_locations(self.db_session)

    def test_should_require_location_parameter(self):
        rv = self.app.get('/devices/submissions/tot_1', headers=settings.header)
        self.assertEqual(rv.status_code, 400)
        error_message = json.loads(rv.data.decode("utf-8")).get('message')
        self.assertIn("location", error_message)
        self.assertIn("Missing required parameter in the JSON", error_message['location'])

    def test_should_return_all_devices_from_single_clinic(self):
        rv = self.app.get('/devices/submissions/tot_1?location=7', headers=settings.header)
        response = json.loads(rv.data.decode("utf-8"))
        clinic_submissions = response['clinicSubmissions']

        self.assertEqual(len(clinic_submissions), 1)
        device_submissions = clinic_submissions[0]['deviceSubmissions']
        self.assertEqual(len(device_submissions), 2)

        actual_device_ids = [sub.get("deviceId") for sub in device_submissions]
        expected_device_ids = ["1", "6"]
        for expected_id, actual_id in zip(expected_device_ids, actual_device_ids):
            self.assertEqual(expected_id, actual_id)

    def test_should_return_all_clinics_within_parent(self):
        rv = self.app.get('/devices/submissions/tot_1?location=1', headers=settings.header)
        response = json.loads(rv.data.decode("utf-8"))
        clinic_submissions = response['clinicSubmissions']

        actual_clinic_ids = [sub.get("clinicId") for sub in clinic_submissions]
        expected_clinic_ids = [7, 8, 10, 11]
        expected_clinic_count = len(expected_clinic_ids)

        self.assertEqual(response['clinicCount'], expected_clinic_count)
        self.assertEqual(len(clinic_submissions), expected_clinic_count)
        for expected_id, actual_id in zip(expected_clinic_ids, actual_clinic_ids):
            self.assertEqual(expected_id, actual_id)
<commit_msg>fix test to use correct return message<commit_after>import json

from werkzeug.exceptions import HTTPException

import meerkat_api
from meerkat_api.resources.devices import DeviceResourceBase
from meerkat_api.test import db_util, settings

class TestDeviceResourceBase(meerkat_api.test.TestCase):
    def setUp(self):
        self.object_under_test = DeviceResourceBase()

    def test_get_sql_alchemy_filters_handles_bad_filters(self):
        bad_format_filter = "not:three_args"
        with self.assertRaises(HTTPException) as http_error:
            self.object_under_test.get_sql_alchemy_filters([bad_format_filter])
        http_exception = http_error.exception
        self.assertEqual(http_exception.code, 404)
        self.assertEqual(http_exception.data['message'], "Incorrect filter: {}".format(bad_format_filter))

    def test_get_sql_alchemy_filters_handles_non_existing_parameters(self):
        bad_argument_filter = "invalidParam:eq:foobar"
        with self.assertRaises(AttributeError) as attribute_error:
            self.object_under_test.get_sql_alchemy_filters([bad_argument_filter])
        the_exception = attribute_error.exception
        actual_argument_name = bad_argument_filter.split(':')[0]
        expected_error_message = "type object 'Data' has no attribute '{}'".format(actual_argument_name)
        self.assertEqual(the_exception.args[0], expected_error_message)

    def test_get_sql_alchemy_filters_handles_non_existing_comparators(self):
        bad_comparator_filter = "id:what?!$%#:NVM"
        with self.assertRaises(NotImplementedError):
            self.object_under_test.get_sql_alchemy_filters([bad_comparator_filter])

    def test_get_sql_alchemy_filters_return_valid_object(self):
        filters = ["id:eq:1", "date:gt:2017-01-01"]
        actual_sql_alchemy_filters = self.object_under_test.get_sql_alchemy_filters(filters)
        _comparator_to_str = {
            "eq": "=",
            "gt": ">"
        }
        for _filter, _actual_sql_filter in zip(filters, actual_sql_alchemy_filters):
            expected_left, expected_comparator, expected_right = _filter.split(":")
            expected = {
                "left": 'data.' + expected_left,
                "comparator": _comparator_to_str[expected_comparator],
                "right": expected_right
            }
            actual = {
                "left": str(_actual_sql_filter.left),
                "comparator": str(_actual_sql_filter).split()[1],
                "right": _actual_sql_filter.right.effective_value
            }

            for key in expected.keys():
                self.assertEqual(expected[key], actual[key])

    def test_get_variable_count_for_device_id(self):
        db_util.insert_cases(self.db_session, "public_health_report")
        device_id = "1"
        variable_id = "gen_1"
        actual = DeviceResourceBase._get_variable_count_for_deivce_id(device_id, variable_id, [])
        expected = {'deviceId': device_id, 'variable': variable_id, 'submissionsCount': 3}
        self.assertEqual(expected, actual)

    def test_get_variable_count_for_deivce_id_should_return_zero_for_no_data(self):
        db_util.insert_cases(self.db_session, "public_health_report")
        device_id = "4"
        variable_id = "gen_1"
        actual = DeviceResourceBase._get_variable_count_for_deivce_id(device_id, variable_id, [])
        expected = {'deviceId': device_id, 'variable': variable_id, 'submissionsCount': 0}
        self.assertEqual(expected, actual)

class TestDeviceSubmissions(meerkat_api.test.TestCase):
    def setUp(self):
        db_util.insert_cases(self.db_session, "public_health_report")

    def test_existing_device_id_with_submissions(self):
        device_id = '1'
        variable_id = 'tot_1'
        expected_submissions = 4

        actual = self.__get_actual_api_response(device_id, variable_id)
        expected = self.__get_expected_dict_response(device_id, expected_submissions, variable_id)

        self.assertDictEqual(expected, actual)

    def test_existing_device_id_with_no_submissions(self):
        device_id = '1'
        variable_id = 'fake_var_id'
        expected_submissions = 0

        actual = self.__get_actual_api_response(device_id, variable_id)
        expected = self.__get_expected_dict_response(device_id, expected_submissions, variable_id)

        self.assertDictEqual(expected, actual)

    def test_non_existing_device_id(self):
        device_id = '99999000000000000000001'
        variable_id = 'tot_1'
        expected_submissions = 0

        actual = self.__get_actual_api_response(device_id, variable_id)
        expected = self.__get_expected_dict_response(device_id, expected_submissions, variable_id)

        self.assertDictEqual(expected, actual)

    def __get_expected_dict_response(self, device_id, expected_submissions, variable_id):
        expected = {'deviceId': device_id, 'variable': variable_id, 'submissionsCount': expected_submissions}
        return expected

    def __get_actual_api_response(self, device_id, variable_id):
        endpoint_under_test = '/device/{}/submissions/{}'.format(device_id, variable_id)
        rv = self.app.get(endpoint_under_test, headers=settings.header)
        self.assertEqual(rv.status_code, 200)
        actual = json.loads(rv.data.decode("utf-8"))
        return actual

class TestDeviceSubmissionsForLocation(meerkat_api.test.TestCase):
    def setUp(self):
        db_util.insert_cases(self.db_session, "public_health_report")
        db_util.insert_locations(self.db_session)

    def test_should_require_location_parameter(self):
        rv = self.app.get('/devices/submissions/tot_1', headers=settings.header)
        self.assertEqual(rv.status_code, 400)
        error_message = json.loads(rv.data.decode("utf-8")).get('message')
        self.assertIn("location", error_message)
        self.assertIn('Please, provide a location parameter.', error_message['location'])

    def test_should_return_all_devices_from_single_clinic(self):
        rv = self.app.get('/devices/submissions/tot_1?location=7', headers=settings.header)
        response = json.loads(rv.data.decode("utf-8"))
        clinic_submissions = response['clinicSubmissions']

        self.assertEqual(len(clinic_submissions), 1)
        device_submissions = clinic_submissions[0]['deviceSubmissions']
        self.assertEqual(len(device_submissions), 2)

        actual_device_ids = [sub.get("deviceId") for sub in device_submissions]
        expected_device_ids = ["1", "6"]
        for expected_id, actual_id in zip(expected_device_ids, actual_device_ids):
            self.assertEqual(expected_id, actual_id)

    def test_should_return_all_clinics_within_parent(self):
        rv = self.app.get('/devices/submissions/tot_1?location=1', headers=settings.header)
        response = json.loads(rv.data.decode("utf-8"))
        clinic_submissions = response['clinicSubmissions']

        actual_clinic_ids = [sub.get("clinicId") for sub in clinic_submissions]
        expected_clinic_ids = [7, 8, 10, 11]
        expected_clinic_count = len(expected_clinic_ids)

        self.assertEqual(response['clinicCount'], expected_clinic_count)
        self.assertEqual(len(clinic_submissions), expected_clinic_count)
        for expected_id, actual_id in zip(expected_clinic_ids, actual_clinic_ids):
            self.assertEqual(expected_id, actual_id)
<|endoftext|>


<commit_before>from random import shuffle, random, choice, randint

def to_position(something):
    """Converts something (thing/position) to a position tuple."""
    if isinstance(something, tuple):
        return something
    else:
        return something.position

def distance(a, b):
    """Calculates distance between two positions or things."""
    x1, y1 = to_position(a)
    x2, y2 = to_position(b)

    return abs(x1 - x2) + abs(y1 - y2)

def distance_draw_solver(a, b):
    x1, y1 = to_position(a)
    x2, y2 = to_position(b)
    return max([abs(x1 - x2), abs(y1 - y2)])

def sort_by_distance(something, others):
    def by_distance(other):
        return (distance(something, other),
                distance_draw_solver(something, other))
    sorted_others = list(sorted(others, key=by_distance))
    if len(sorted_others) > 1 and distance(something, sorted_others[0]) == distance(something, sorted_others[1]):
        x1, y1 = to_position(sorted_others[0])
        x2, y2 = to_position(something)
        delta_x = abs(x1 - x2)
        delta_y = abs(y1 - y2)
        max_value = max([delta_x, delta_y])
        min_value = min([delta_x, delta_y])
        cut_point = min_value / (max_value + min_value)

        if random() < cut_point:
            sorted_others[0], sorted_others[1] = sorted_others[1], sorted_others[0]

    return sorted_others

def closest(something, others):
    """Returns the closest other to something (things/positions)."""
    if others:
        return sort_by_distance(something, others)[0]

def adjacent_positions(something):
    """Calculates the 4 adjacent positions of something (thing/position)."""
    position = to_position(something)
    deltas = ((0, 1),
              (0, -1),
              (1, 0),
              (-1, 0))

    return [(position[0] + delta[0],
             position[1] + delta[1])
            for delta in deltas]

def possible_moves(something, things):
    """Calculates the possible moves for a thing."""
    positions = [position for position in adjacent_positions(something)
                 if things.get(position) is None]

    return positions

def inside_map(something, size):
    """Check if a position or a thing is inside the map."""
    position = to_position(something)
    return 0 <= position[0] < size[0] and 0 <= position[1] < size[1]

def closes_empty_position(something, world):
    """Get the closest empty position to another thing or position."""
    position = to_position(something)
    fringe = [position]
    seen = set()

    while fringe:
        position = fringe.pop(0)
        seen.add(position)
        if position not in world.things:
            return position
        else:
            adjacents = adjacent_positions(position)
            shuffle(adjacents)
            for adjacent in adjacents:
                if adjacent not in seen and inside_map(adjacent, world.size):
                    fringe.append(adjacent)

    return None
<commit_msg>Utility to get circle positions<commit_after>from random import shuffle, random, choice, randint

def to_position(something):
    """Converts something (thing/position) to a position tuple."""
    if isinstance(something, tuple):
        return something
    else:
        return something.position

def distance(a, b):
    """Calculates distance between two positions or things."""
    x1, y1 = to_position(a)
    x2, y2 = to_position(b)

    return abs(x1 - x2) + abs(y1 - y2)

def distance_draw_solver(a, b):
    x1, y1 = to_position(a)
    x2, y2 = to_position(b)
    return max([abs(x1 - x2), abs(y1 - y2)])

def sort_by_distance(something, others):
    def by_distance(other):
        return (distance(something, other),
                distance_draw_solver(something, other))
    sorted_others = list(sorted(others, key=by_distance))
    if len(sorted_others) > 1 and distance(something, sorted_others[0]) == distance(something, sorted_others[1]):
        x1, y1 = to_position(sorted_others[0])
        x2, y2 = to_position(something)
        delta_x = abs(x1 - x2)
        delta_y = abs(y1 - y2)
        max_value = max([delta_x, delta_y])
        min_value = min([delta_x, delta_y])
        cut_point = min_value / (max_value + min_value)

        if random() < cut_point:
            sorted_others[0], sorted_others[1] = sorted_others[1], sorted_others[0]

    return sorted_others

def closest(something, others):
    """Returns the closest other to something (things/positions)."""
    if others:
        return sort_by_distance(something, others)[0]

def adjacent_positions(something):
    """Calculates the 4 adjacent positions of something (thing/position)."""
    position = to_position(something)
    deltas = ((0, 1),
              (0, -1),
              (1, 0),
              (-1, 0))

    return [(position[0] + delta[0],
             position[1] + delta[1])
            for delta in deltas]

def possible_moves(something, things):
    """Calculates the possible moves for a thing."""
    positions = [position for position in adjacent_positions(something)
                 if things.get(position) is None]

    return positions

def inside_map(something, size):
    """Check if a position or a thing is inside the map."""
    position = to_position(something)
    return 0 <= position[0] < size[0] and 0 <= position[1] < size[1]

def closes_empty_position(something, world):
    """Get the closest empty position to another thing or position."""
    position = to_position(something)
    fringe = [position]
    seen = set()

    while fringe:
        position = fringe.pop(0)
        seen.add(position)
        if position not in world.things:
            return position
        else:
            adjacents = adjacent_positions(position)
            shuffle(adjacents)
            for adjacent in adjacents:
                if adjacent not in seen and inside_map(adjacent, world.size):
                    fringe.append(adjacent)

    return None

def circle_positions(center, radius):
    """Get the positions of a circle."""
    x_center, y_center = center
    return [(x, y)
            for x in range(x_center - radius, x_center + radius)
            for y in range(y_center - radius, y_center + radius)
            if distance((x, y), center) <= radius]
<|endoftext|>


<commit_before>
from metafunctions.tests.util import BaseTestCase
from metafunctions.util import store, recall, node, highlight_current_function
from metafunctions.core import MetaFunction, SimpleFunction

class TestUnit(BaseTestCase):
    def test_node_bind(self):
        '''
        Node bind rules:
        The MetaFunction recieved in a base function when bind is true is the
        function that was called. E.g., if a SimpleFunction is called directly, meta will be that
        SimpleFunction itself. However, if the SimpleFunction is contained within a hierarchy of
        other MetaFunction, meta will be the highest level (i.e., outermost) Metafunction.
        '''
        @node(bind=True)
        def a_(meta, x):
            self.assertIsInstance(meta, MetaFunction)
            meta.data['a'] = 'b'
            return x + 'a'
        @node(bind=True)
        def f(meta, x):
            return x + meta.data.get('a', 'f')

        self.assertEqual(a('_'), '_a')
        self.assertEqual(f('_'), '_f')

        cmp = a_ | f
        self.assertEqual(cmp('_'), '_ab')
        cmp = f | a_ | a_ | f + f
        self.assertEqual(cmp('_'), '_faab_faab')

    def test_node_bracketless(self):
        '''
        I'm allowing the node decorator to be applied without calling because this is how both
        celery and function_pipes work.
        '''
        @node
        def a(x):
            return x + 'a'
        @node()
        def b(x):
            return x + 'b'

        self.assertIsInstance(a, SimpleFunction)
        self.assertIsInstance(b, SimpleFunction)
        self.assertEqual((b|a)('_'), '_ba')

    def test_store(self):
        abc = a | b | store('output') | c
        big = (a | b | c + store('ab') + store('ab2') | store('abc') | recall('ab') + recall('ab2') |
               c + recall('abc'))

        self.assertEqual(abc('_'), '_abc')
        self.assertEqual(abc.data['output'], '_ab')
        self.assertEqual(big('_'), '_ab_abc_abc_ab_ab')

    def test_recall(self):
        a.data['k'] = 'secret'

        cmp = a + b | store('k') | c + recall('k')
        self.assertEqual(cmp('_'), '_a_bc_a_b')

        cmp = a + b | store('k') | c + recall('k') | recall('k', from_meta=a)
        self.assertEqual(cmp('_'), 'secret')

    def test_str_store(self):
        self.fail('Fix store str')

    def test_str_recall(self):
        self.fail('Fix recall str')

    def test_highlight_current_function(self):
        fmt_index = 6

        @node
        def ff(x):
            return x + 'F'

        @node(bind=True)
        def f(meta, x):
            if len(meta._called_functions) == 6:
                location_string = highlight_current_function(meta, use_color=False)
                location_string_color = highlight_current_function(meta, use_color=True)
                self.assertEqual(location_string, '(a | b | ff | f | f | ->f<- | f | f)')
                self.assertEqual(location_string_color,
                        '(a | b | ff | f | f | \x1b[31m->f<-\x1b[0m | f | f)')
                self.assertEqual(x, '_abFff')
            return x + 'f'

        pipe = a | b | ff | f | f | f | f | f
        pipe('_')

        af = a + f
        af('_')
        curr_f = highlight_current_function(af, use_color=False)
        self.assertEqual(curr_f, '(a + ->f<-)')

@node
def a(x):
    return x + 'a'
@node()
def b(x):
    return x + 'b'
@node()
def c(x):
    return x + 'c'
<commit_msg>Modify store and recall str tests<commit_after>
from metafunctions.tests.util import BaseTestCase
from metafunctions.util import store, recall, node, highlight_current_function
from metafunctions.core import MetaFunction, SimpleFunction

class TestUnit(BaseTestCase):
    def test_node_bind(self):
        '''
        Node bind rules:
        The MetaFunction recieved in a base function when bind is true is the
        function that was called. E.g., if a SimpleFunction is called directly, meta will be that
        SimpleFunction itself. However, if the SimpleFunction is contained within a hierarchy of
        other MetaFunction, meta will be the highest level (i.e., outermost) Metafunction.
        '''
        @node(bind=True)
        def a_(meta, x):
            self.assertIsInstance(meta, MetaFunction)
            meta.data['a'] = 'b'
            return x + 'a'
        @node(bind=True)
        def f(meta, x):
            return x + meta.data.get('a', 'f')

        self.assertEqual(a('_'), '_a')
        self.assertEqual(f('_'), '_f')

        cmp = a_ | f
        self.assertEqual(cmp('_'), '_ab')
        cmp = f | a_ | a_ | f + f
        self.assertEqual(cmp('_'), '_faab_faab')

    def test_node_bracketless(self):
        '''
        I'm allowing the node decorator to be applied without calling because this is how both
        celery and function_pipes work.
        '''
        @node
        def a(x):
            return x + 'a'
        @node()
        def b(x):
            return x + 'b'

        self.assertIsInstance(a, SimpleFunction)
        self.assertIsInstance(b, SimpleFunction)
        self.assertEqual((b|a)('_'), '_ba')

    def test_store(self):
        abc = a | b | store('output') | c
        big = (a | b | c + store('ab') + store('ab2') | store('abc') | recall('ab') + recall('ab2') |
               c + recall('abc'))

        self.assertEqual(abc('_'), '_abc')
        self.assertEqual(abc.data['output'], '_ab')
        self.assertEqual(big('_'), '_ab_abc_abc_ab_ab')

    def test_recall(self):
        a.data['k'] = 'secret'

        cmp = a + b | store('k') | c + recall('k')
        self.assertEqual(cmp('_'), '_a_bc_a_b')

        cmp = a + b | store('k') | c + recall('k') | recall('k', from_meta=a)
        self.assertEqual(cmp('_'), 'secret')

    def test_str_store(self):
        #this should be possible
        self.assertEqual(str(store('key')), "store('key')")

    def test_str_recall(self):
        self.assertEqual(str(recall('key')), "recall('key')")

    def test_highlight_current_function(self):
        fmt_index = 6

        @node
        def ff(x):
            return x + 'F'

        @node(bind=True)
        def f(meta, x):
            if len(meta._called_functions) == 6:
                location_string = highlight_current_function(meta, use_color=False)
                location_string_color = highlight_current_function(meta, use_color=True)
                self.assertEqual(location_string, '(a | b | ff | f | f | ->f<- | f | f)')
                self.assertEqual(location_string_color,
                        '(a | b | ff | f | f | \x1b[31m->f<-\x1b[0m | f | f)')
                self.assertEqual(x, '_abFff')
            return x + 'f'

        pipe = a | b | ff | f | f | f | f | f
        pipe('_')

        af = a + f
        af('_')
        curr_f = highlight_current_function(af, use_color=False)
        self.assertEqual(curr_f, '(a + ->f<-)')

@node
def a(x):
    return x + 'a'
@node()
def b(x):
    return x + 'b'
@node()
def c(x):
    return x + 'c'
<|endoftext|>