Exemple #1
0
 def __init__(self, configfile, configID, processfile):
     self.logger = self.loadLogger()
     self.processfile = processfile
     self.cmodules = self.loadProcesses()
     self.configfile = configfile
     self.currentconfig = configID  #multiple configs possible
     # connect to db
     self.db = DBI(configfile)
     self.db.getconn()
 def setUp(self):
     self.resourcesdir = join('..', 'resources')
     self.processfile = join(self.resourcesdir, 'processes_test.yaml')
     self.configfile = join(self.resourcesdir, 'autoconfig_test.db')
     self.dbi = DBI(self.configfile)
     self.dbi.getconn()
     self.currentconfig = 'test'
     self.controller = Controller(self.configfile, self.currentconfig,
                                  self.processfile)
     # TEST DATA
     self.datafile = "D:\\Data\\Csv\\input\\control\\Brain10_Image.csv"
     self.outputdir = "D:\\Data\\Csv\\output"
     self.testcolumn = 'Count_ColocalizedGAD_DAPI_Objects'
Exemple #3
0
 def __init__(self, controller, wxObject, modules, outputdir, filenames, row, processname, showplots):
     """Init Worker Thread Class."""
     threading.Thread.__init__(self)
     self.controller = controller
     self.config = self.controller.db.getConfig(self.controller.currentconfig)
     self.db = DBI(self.controller.configfile)
     self.wxObject = wxObject
     self.filenames = filenames
     self.output = outputdir
     self.row = row
     self.showplots = showplots
     self.processname = processname
     (self.module_name,self.class_name) = modules
     logger = logging.getLogger(processname)
class TestDBquery(unittest.TestCase):
    def setUp(self):
        configdb = join('..','resources', 'autoconfig_test.db')
        self.dbi = DBI(configdb)
        self.dbi.getconn()

    def tearDown(self):
        self.dbi.conn.close()

    def test_getConfig(self):
        configid = 'general'
        data = self.dbi.getConfig(configid)
        expected = 0
        self.assertGreater(len(data),expected)

    def test_getConfigByName(self):
        group = 'general'
        test = 'BINWIDTH'
        expected = 10
        data = self.dbi.getConfigByName(group,test)
        self.assertEqual(int(data),expected)

    def test_getConfigByName_None(self):
        group = 'general'
        test = 'BINW'
        expected = None
        data = self.dbi.getConfigByName(group,test)
        self.assertEqual(data,expected)

    def test_getConfigIds(self):
        data = self.dbi.getConfigIds()
        print('IDS:', data)
        self.assertGreater(len(data),0)

    def test_updateConfig(self):
        configid='general'
        configlist = [('BINWIDTH',10,'general'),('COLUMN','TestData','general'),('MINRANGE',0,'general'),('MAXRANGE',100,'general')]
        cnt = self.dbi.addConfig(configid,configlist)
        expected = len(configlist)
        self.assertEqual(expected,cnt)

    def test_updateConfig_Secondset(self):
        configid = 'test'
        configlist = [('BINWIDTH', 10, configid), ('COLUMN', 'TestData', configid), ('MINRANGE', 0, configid),('MAXRANGE', 100, configid)]
        cnt = self.dbi.addConfig(configid, configlist)
        expected = len(configlist)
        self.assertEqual(expected, cnt)

    def test_updateConfig_duplicate(self):
        configid='general'
        configlist = [('BINWIDTH',20,'general'),('COLUMN','TestData2','general'),('MINRANGE',0,'general'),('MAXRANGE',100,'general')]
        cnt = self.dbi.addConfig(configid,configlist)
        expected = len(configlist)
        self.assertEqual(expected,cnt)
Exemple #5
0
 def __init__(self, parent):
     super(ProcessRunPanel, self).__init__(parent)
     self.loadController()
     self.db = DBI(self.controller.configfile)
     self.db.getconn()
     # self.controller = parent.controller
     # Bind timer event
     # self.Bind(wx.EVT_TIMER, self.progressfunc, self.controller.timer)
     # processes = [p['caption'] for p in self.controller.processes]
     # self.m_checkListProcess.AppendItems(processes)
     # Set up event handler for any worker thread results
     EVT_RESULT(self, self.progressfunc)
     # EVT_CANCEL(self, self.stopfunc)
     # Set timer handler
     self.start = {}
Exemple #6
0
class ProcessRunPanel(ProcessPanel):
    def __init__(self, parent):
        super(ProcessRunPanel, self).__init__(parent)
        self.loadController()
        self.db = DBI(self.controller.configfile)
        self.db.getconn()
        # self.controller = parent.controller
        # Bind timer event
        # self.Bind(wx.EVT_TIMER, self.progressfunc, self.controller.timer)
        # processes = [p['caption'] for p in self.controller.processes]
        # self.m_checkListProcess.AppendItems(processes)
        # Set up event handler for any worker thread results
        EVT_RESULT(self, self.progressfunc)
        # EVT_CANCEL(self, self.stopfunc)
        # Set timer handler
        self.start = {}

    def loadController(self):
        self.controller = self.Parent.controller
        processes = [self.controller.processes[p]['caption'] for p in self.controller.processes]
        self.m_checkListProcess.Clear()
        self.m_checkListProcess.AppendItems(processes)

    def OnShowDescription(self, event):
        print(event.String)

        desc = [self.controller.processes[p]['description'] for p in self.controller.processes if
                self.controller.processes[p]['caption'] == event.String]
        filesIn = [self.controller.processes[p]['filesin'] for p in self.controller.processes if
                   self.controller.processes[p]['caption'] == event.String]
        filesOut = [self.controller.processes[p]['filesout'] for p in self.controller.processes if
                    self.controller.processes[p]['caption'] == event.String]
        # Load from Config
        filesIn = [self.controller.db.getConfigByName(self.controller.currentconfig,f) for f in filesIn[0].split(", ")]
        filesOut = [self.controller.db.getConfigByName(self.controller.currentconfig,f) for f in filesOut[0].split(", ")]
        # Load to GUI
        self.m_stTitle.SetLabelText(event.String)
        self.m_stDescription.SetLabelText(desc[0])
        self.m_stFilesin.SetLabelText(", ".join(filesIn))
        self.m_stFilesout.SetLabelText(", ".join(filesOut))
        self.Layout()

    def progressfunc(self, msg):
        """
        Update progress bars in table - multithreaded
        :param count:
        :param row:
        :param col:
        :return:
        """
        (count, row, i, total, process) = msg.data
        print("\nProgress updated: ", time.ctime())
        print('count = ', count)
        status = "%d of %d files " % (i, total)
        if count == 0:
            self.m_dataViewListCtrlRunning.AppendItem([process, count, "Pending"])
            self.start[process] = time.time()
        elif count < 0:
            self.m_dataViewListCtrlRunning.SetValue("ERROR in process - see log file", row=row, col=2)
            self.m_btnRunProcess.Enable()
        elif count < 100:
            self.m_dataViewListCtrlRunning.SetValue(count, row=row, col=1)
            self.m_dataViewListCtrlRunning.SetValue("Running " + status, row=row, col=2)
            self.m_stOutputlog.SetLabelText("Running: %s ...please wait" % process)
        else:
            if process in self.start:
                endtime = time.time() - self.start[process]
                status = "%s (%d secs)" % (status, endtime)
            print(status)
            self.m_dataViewListCtrlRunning.SetValue(count, row=row, col=1)
            self.m_dataViewListCtrlRunning.SetValue("Done " + status, row=row, col=2)
            self.m_btnRunProcess.Enable()
            self.m_stOutputlog.SetLabelText("Completed process %s" % process)

    def getFilePanel(self):
        """
        Get access to filepanel
        :return:
        """
        filepanel = None

        for fp in self.Parent.Children:
            if isinstance(fp, FileSelectPanel):
                filepanel = fp
                break
        return filepanel

    def OnCancelScripts(self, event):
        """
        Find a way to stop processes
        :param event:
        :return:
        """
        self.controller.shutdown()
        print("Cancel multiprocessor")
        event.Skip()

    def OnRunScripts(self, event):
        """
        Run selected scripts sequentially - updating progress bars
        :param e:
        :return:
        """
        # Clear processing window
        self.m_dataViewListCtrlRunning.DeleteAllItems()
        # Disable Run button
        # self.m_btnRunProcess.Disable()
        btn = event.GetEventObject()
        btn.Disable()
        # Get selected processes
        selections = self.m_checkListProcess.GetCheckedStrings()
        print("Processes selected: ", len(selections))
        showplots = self.m_cbShowplots.GetValue()
        # Get data from other panels
        filepanel = self.getFilePanel()
        filenames = {'all': []}
        groups = filepanel.m_cbGroups.GetItems()
        for g in groups:
            filenames[g]=[]

        num_files = filepanel.m_dataViewListCtrl1.GetItemCount()
        outputdir = filepanel.txtOutputdir.GetValue()  # for batch processes
        print('All Files:', num_files)
        try:
            self.db.getconn()
            if len(selections) > 0 and num_files > 0:
                # Get selected files and sort into groups
                for i in range(0, num_files):
                    if filepanel.m_dataViewListCtrl1.GetToggleValue(i, 0):
                        fname = filepanel.m_dataViewListCtrl1.GetValue(i, 2)
                        group = filepanel.m_dataViewListCtrl1.GetValue(i, 1)
                        if not isdir(fname):
                            filenames['all'].append(fname)
                            if len(group) > 0:
                                filenames[group].append(fname)
                print('Selected Files:', len(filenames['all']))
                if len(filenames) <= 0:
                    raise ValueError("No files selected in Files Panel")

                row = 0
                # For each process
                for pcaption in selections:
                    for p in self.controller.processes.keys():
                        if self.controller.processes[p]['caption']==pcaption:
                            break
                    print("processname =", p)
                    self.controller.RunProcess(self, p, outputdir,filenames, row, showplots)
                    row = row + 1

            else:
                if len(selections) <= 0:
                    raise ValueError("No processes selected")
                else:
                    raise ValueError("No files selected - please go to Files Panel and add to list")
        except ValueError as e:
            self.Parent.Warn(e.args[0])
            # Enable Run button
            self.m_btnRunProcess.Enable()
        finally:
            if self.db is not None:
                self.db.closeconn()

    def OnShowLog(self, event):
        """
        Load logfile into viewer
        :param event:
        :return:
        """
        dlg = dlgLogViewer(self)
        logfile = self.controller.logfile
        dlg.tcLog.LoadFile(logfile)
        dlg.ShowModal()
        dlg.Destroy()

    def OnClearWindow(self, event):
        self.m_dataViewListCtrlRunning.DeleteAllItems()
Exemple #7
0
 def __init__(self, parent):
     super(Config, self).__init__(parent)
     self.parent = parent
     self.configdb = join(self.parent.resourcesdir, 'autoconfig.db')
     self.dbi = DBI(self.configdb)
     self.loadController()
Exemple #8
0
class Config(ConfigPanel):
    def __init__(self, parent):
        super(Config, self).__init__(parent)
        self.parent = parent
        self.configdb = join(self.parent.resourcesdir, 'autoconfig.db')
        self.dbi = DBI(self.configdb)
        self.loadController()

    def loadController(self):
        self.controller = self.parent.controller
        self.currentconfig = self.parent.controller.currentconfig
        self.OnLoadData()

    def OnLoadData(self):
        self.dbi.getconn()
        #load config values
        cids = self.dbi.getConfigIds()
        if len(cids)>0:
            self.cboConfigid.Set(cids)
            #configid = self.cboConfigid.GetStringSelection()
            rownum =0
            if self.currentconfig in cids:
                selection = self.cboConfigid.FindString(self.currentconfig)
                self.cboConfigid.SetSelection(selection)
                conf = self.dbi.getConfig(self.currentconfig)
            else:
                selection = self.cboConfigid.FindString(cids[0])
                self.cboConfigid.SetSelection(selection)
                conf = self.dbi.getConfig(cids[0])
            if conf is not None:
                for k in conf.keys():
                    self.m_grid1.SetCellValue(rownum, 0, k)
                    self.m_grid1.SetCellValue(rownum, 1, conf[k])
                    rownum += 1
                self.m_grid1.AutoSizeColumns()
                self.m_grid1.AutoSize()
        self.dbi.closeconn()

    def OnLoadConfig(self,event):
        self.dbi.getconn()
        #load config values
        configid = self.cboConfigid.GetValue()
        try:
            rownum =0
            conf = self.dbi.getConfig(configid)
            if conf is not None:
                self.m_grid1.ClearGrid()
                for k in conf.keys():
                    self.m_grid1.SetCellValue(rownum, 0, k)
                    self.m_grid1.SetCellValue(rownum, 1, conf[k])
                    rownum += 1
                self.m_grid1.AutoSizeColumns()
                self.m_grid1.AutoSize()
            #Notify other controllers
            self.parent.controller.currentconfig = configid
            # reload other panels
            for fp in self.parent.Children:
                if isinstance(fp, wx.Panel) and self.__class__ != fp.__class__:
                    fp.loadController()
            # notification
            msg = "Config loaded: %s" % configid
            self.Parent.Warn(msg)
        except Exception as e:
            self.Parent.Warn(e.args[0])
        finally:
            self.dbi.closeconn()


    def OnSaveConfig(self, event):
        self.dbi.getconn()
        configid = self.cboConfigid.GetValue()
        configlist=[]
        data = self.m_grid1.GetTable()
        for rownum in range(0, data.GetRowsCount()):
            if not data.IsEmptyCell(rownum, 0):
                configlist.append((self.m_grid1.GetCellValue(rownum, 0),self.m_grid1.GetCellValue(rownum, 1),configid))
        #print('Saved config:', configlist)
        # Save to DB
        cnt = self.dbi.addConfig(configid,configlist)
        # Load as options
        cids = self.dbi.getConfigIds()
        if len(cids) > 0:
            self.cboConfigid.Set(cids)
            selection = self.cboConfigid.FindString(configid)
            self.cboConfigid.SetSelection(selection)
        # Load controller
        self.parent.controller.currentconfig = configid
        #reload other panels
        for fp in self.parent.Children:
            if isinstance(fp, wx.Panel) and self.__class__ != fp.__class__:
                fp.loadController()
        #notification
        msg = "Config saved: %s" % configid
        self.Parent.Warn(msg)
        self.dbi.closeconn()

    def OnAddRow(self, event):
        self.m_grid1.AppendRows(1, True)
 def __init__(self, parent):
     super(Config, self).__init__(parent)
     self.parent = parent
     self.configdb = self.parent.configfile
     self.dbi = DBI(self.configdb)
     self.loadController()
Exemple #10
0
 def setUp(self):
     configdb = join('..', 'resources', 'autoconfig_test.db')
     self.dbi = DBI(configdb)
     self.dbi.getconn()
Exemple #11
0
class TestDBquery(unittest.TestCase):
    def setUp(self):
        configdb = join('..', 'resources', 'autoconfig_test.db')
        self.dbi = DBI(configdb)
        self.dbi.getconn()

    def tearDown(self):
        self.dbi.conn.close()

    def test_getConfig(self):
        configid = 'test'
        data = self.dbi.getConfig(configid)
        expected = 0
        self.assertGreater(len(data), expected)

    def test_getConfigALL(self):
        configid = 'test'
        data = self.dbi.getConfigALL(configid)
        expected = 0
        self.assertGreater(len(data), expected)

    def test_getConfigByName(self):
        group = 'test'
        test = 'BINWIDTH'
        expected = 20
        data = self.dbi.getConfigByName(group, test)
        self.assertEqual(int(data), expected)

    def test_getConfigByName_None(self):
        group = 'test'
        test = 'BINW'
        expected = None
        data = self.dbi.getConfigByName(group, test)
        self.assertEqual(data, expected)

    def test_getConfigIds(self):
        data = self.dbi.getConfigIds()
        print('IDS:', data)
        self.assertGreater(len(data), 0)

    def test_updateConfig(self):
        configid = 'test'
        configlist = [
            ('BINWIDTH', 10, 'test', "Bin width for histograms"),
            ('COLUMN', 'TestData', 'test', "Column name for histograms"),
            ('MINRANGE', 0, 'test', "Minimum range of histograms bins"),
            ('MAXRANGE', 100, 'test', "Maximum range of histograms bins")
        ]
        cnt = self.dbi.addConfig(configid, configlist)
        expected = len(configlist)
        self.assertEqual(expected, cnt)

    def test_updateConfig_Secondset(self):
        configid = 'test'
        configlist = [
            ('BINWIDTH', 10, configid, "Bin width for histograms"),
            ('COLUMN', 'TestData', configid, "Column name for histograms"),
            ('MINRANGE', 0, configid, "Minimum range of histograms bins"),
            ('MAXRANGE', 100, configid, "Maximum range of histograms bins")
        ]
        cnt = self.dbi.addConfig(configid, configlist)
        expected = len(configlist)
        self.assertEqual(expected, cnt)

    def test_updateConfig_duplicate(self):
        configid = 'test'
        configlist = [
            ('BINWIDTH', 20, 'test', "Bin width for histograms"),
            ('COLUMN', 'TestData2', 'test', "Column name for histograms"),
            ('MINRANGE', 5, 'test', "Minimum range of histograms bins"),
            ('MAXRANGE', 50, 'test', "Maximum range of histograms bins")
        ]
        cnt = self.dbi.addConfig(configid, configlist)
        expected = len(configlist)
        self.assertEqual(expected, cnt)
Exemple #12
0
class Controller():
    def __init__(self, configfile, configID, processfile):
        self.logger = self.loadLogger()
        self.processfile = processfile
        self.cmodules = self.loadProcesses()
        self.configfile = configfile
        self.currentconfig = configID  #multiple configs possible
        # connect to db
        self.db = DBI(configfile)
        self.db.getconn()

    def loadProcesses(self):
        pf = None
        try:
            pf = open(self.processfile, 'rb')
            self.processes = yaml.load(pf)
            cmodules = {}
            for p in self.processes:
                msg = "Controller:LoadProcessors: loading %s=%s" % (
                    p, self.processes[p]['caption'])
                logging.debug(msg)
                module_name = self.processes[p]['modulename']
                class_name = self.processes[p]['classname']
                cmodules[p] = (module_name, class_name)
            return cmodules
        except Exception as e:
            raise e
        finally:
            if pf is not None:
                pf.close()

    def loadLogger(self, outputdir=None, expt=''):
        #### LoggingConfig
        logger.setLevel(logging.INFO)
        homedir = expanduser("~")
        if outputdir is not None and access(outputdir, R_OK):
            homedir = outputdir
        if len(expt) > 0:
            expt = expt + "_"
        if not access(join(homedir, "logs"), R_OK):
            mkdir(join(homedir, "logs"))
        self.logfile = join(homedir, "logs", expt + 'analysis.log')
        handler = RotatingFileHandler(filename=self.logfile,
                                      maxBytes=10000000,
                                      backupCount=10)
        formatter = logging.Formatter(
            '[ %(asctime)s %(levelname)-4s ] %(filename)s %(lineno)d : (%(threadName)-9s) %(message)s'
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        return logger

    # ----------------------------------------------------------------------
    # def loadConfig(self, config=None):
    #     """
    #     Load from config file or config object
    #     :param config:
    #     :return:
    #     """
    #     try:
    #         if config is not None and isinstance(config, ConfigObj):
    #             logger.info("Loading config obj:%s", config.filename)
    #         elif isinstance(config, str) and access(config, R_OK):
    #             logger.info("Loading config from file:%s", config)
    #             config = ConfigObj(config)
    #         else:
    #             logger.warning('No config file found')
    #             config = ConfigObj()
    #
    #     except IOError as e:
    #         logging.error(e)
    #     except ValueError as e:
    #         logging.error(e)
    #
    #     return config

    # ----------------------------------------------------------------------
    def RunCompare(self, wxGui, indirs, outputdir, prefixes, searchtext):
        """
        Comparison of groups
        :param wxGui:
        :param indirs:
        :param outputdir:
        :param prefixes:
        :param searchtext:
        :return:
        """
        pass

    # ----------------------------------------------------------------------
    def RunProcess(self,
                   wxGui,
                   process,
                   outputdir,
                   filenames,
                   row,
                   showplots=False):
        """
        Instantiate Thread with type for Process
        :param wxGui:
        :param filenames:
        :param type:
        :param row:
        :return:
        """

        type = self.processes[process]['href']
        processname = self.processes[process]['caption']
        filesIn = []
        for f in self.processes[process]['filesin'].split(", "):
            fin = self.db.getConfigByName(self.currentconfig, f)
            if fin is not None:
                filesIn.append(fin)
            else:
                filesIn.append(f)
        filenames = CheckFilenames(filenames, filesIn)
        # filesout = self.processes[process]['filesout'] #TODO link up with module config?
        # suffix = self.db.getConfigByName(self.currentconfig,filesout)
        if self.processes[process]['output'] == 'local':
            outputdir = self.processes[process]['output']
            filenames = filenames['all']

        if len(filenames) > 0:
            logger.info("Load Process Threads: %s [row: %d]", type, row)
            wx.PostEvent(wxGui,
                         ResultEvent((0, row, 0, len(filenames), processname)))
            t = ProcessThread(self, wxGui, self.cmodules[process], outputdir,
                              filenames, row, processname, showplots)
            t.start()
            logger.info("Running Thread: %s", type)
        else:
            logger.error("No files to process")
            raise ValueError("No matched files to process")

    # ----------------------------------------------------------------------

    def shutdown(self):
        logger.info('Close extra thread')
        t = threading.current_thread()
        #print("Thread counter:", threading.main_thread())
        if t != threading.main_thread() and t.is_alive():
            logger.info('Shutdown: closing %s', t.getName())
            t.terminate()
Exemple #13
0
class ProcessThread(threading.Thread):
    """Multi Worker Thread Class."""

    # ----------------------------------------------------------------------
    def __init__(self, controller, wxObject, modules, outputdir, filenames,
                 row, processname, showplots):
        """Init Worker Thread Class."""
        threading.Thread.__init__(self)
        self.controller = controller
        self.config = self.controller.db.getConfig(
            self.controller.currentconfig)
        self.db = DBI(self.controller.configfile)
        self.wxObject = wxObject
        self.filenames = filenames
        self.output = outputdir
        self.row = row
        self.showplots = showplots
        self.processname = processname
        (self.module_name, self.class_name) = modules
        logger = logging.getLogger(processname)
        # self.start()  # start the thread

    # ----------------------------------------------------------------------
    def run(self):
        i = 0
        total_files = 0
        try:
            event.set()
            lock.acquire(True)
            q = dict()
            # connect to db
            self.db.getconn()
            if isinstance(self.filenames, dict):
                batch = True
                total_files = len(self.filenames) - 1
                i = 0
                for group in self.filenames.keys():
                    if group == 'all' or len(self.filenames[group]) <= 0:
                        continue
                    count = (i / total_files) * 100
                    msg = "PROCESS THREAD (batch):%s run: count=%d of %d (%d percent)" % (
                        self.processname, i, total_files, count)
                    print(msg)
                    logger.info(msg)
                    #TODO fix this
                    wx.PostEvent(
                        self.wxObject,
                        ResultEvent((count, self.row, i + 1, total_files,
                                     self.processname)))
                    self.processBatch(self.filenames[group], q, group)
                    i += 1

            else:
                batch = False
                files = self.filenames
                total_files = len(files)
                for i in range(total_files):
                    count = (i + 1 / total_files) * 100
                    msg = "PROCESS THREAD: %s run: count=%d of %d (%d percent)" % (
                        self.processname, i + 1, total_files, count)
                    print(msg)
                    logger.info(msg)
                    wx.PostEvent(
                        self.wxObject,
                        ResultEvent((count, self.row, i + 1, total_files,
                                     self.processname)))
                    self.processData(files[i], q)

            wx.PostEvent(
                self.wxObject,
                ResultEvent((100, self.row, total_files, total_files,
                             self.processname)))
        except Exception as e:
            wx.PostEvent(
                self.wxObject,
                ResultEvent(
                    (-1, self.row, i + 1, total_files, self.processname)))
            logging.error(e)
        finally:
            logger.info('Finished ProcessThread')
            # self.terminate()
            lock.release()
            event.clear()
            # connect to db
            self.db.closeconn()

    # ----------------------------------------------------------------------
    def processData(self, filename, q):
        """
        Run module here - can modify according to class if needed
        :param filename: data file to process
        :param q: queue for results
        :return:
        """
        logger.info("Process Data with file: %s", filename)
        # create local subdir for output
        if self.output == 'local':
            inputdir = dirname(filename)
            if 'processed' in inputdir:
                outputdir = inputdir
            else:
                outputdir = join(inputdir, 'processed')
            if not exists(outputdir):
                mkdir(outputdir)
        else:
            outputdir = self.output
        # Instantiate module
        module = importlib.import_module(self.module_name)
        class_ = getattr(module, self.class_name)
        mod = class_(filename, outputdir, showplots=self.showplots)
        # Load all params required for module - get list from module
        cfg = mod.getConfigurables()
        for c in cfg.keys():
            cfg[c] = self.db.getConfigByName(self.controller.currentconfig, c)
            msg = "Process Data: config set: %s=%s" % (c, str(cfg[c]))
            print(msg)
            logger.debug(msg)
        mod.setConfigurables(cfg)
        if mod.data is not None:
            q[filename] = mod.run()
        else:
            q[filename] = None

    def processBatch(self, filelist, q, group=None):
        """
        Run module here - can modify according to class if needed
        :param filename: data file to process
        :param q: queue for results
        :return:
        """
        logger.info("Process Batch with filelist: %d", len(filelist))
        outputdir = self.output

        # Instantiate module
        module = importlib.import_module(self.module_name)
        class_ = getattr(module, self.class_name)
        mod = class_(filelist, outputdir, showplots=self.showplots)
        # Load all params required for module - get list from module
        cfg = mod.getConfigurables()
        for c in cfg.keys():
            cfg[c] = self.db.getConfigByName(self.controller.currentconfig, c)
            msg = "Process Batch: config set: %s=%s" % (c, str(cfg[c]))
            logger.debug(msg)
        mod.setConfigurables(cfg)
        if group is not None:
            mod.prefix = group
            q[group] = mod.run()
        else:
            q[mod.base] = mod.run()

    # ----------------------------------------------------------------------
    def terminate(self):
        logger.info("Terminating Filter Thread")
        self.terminate()
class TestController(unittest.TestCase):
    def setUp(self):
        self.resourcesdir = join('..', 'resources')
        self.processfile = join(self.resourcesdir, 'processes_test.yaml')
        self.configfile = join(self.resourcesdir, 'autoconfig_test.db')
        self.dbi = DBI(self.configfile)
        self.dbi.getconn()
        self.currentconfig = 'test'
        self.controller = Controller(self.configfile, self.currentconfig,
                                     self.processfile)
        # TEST DATA
        self.datafile = "D:\\Data\\Csv\\input\\control\\Brain10_Image.csv"
        self.outputdir = "D:\\Data\\Csv\\output"
        self.testcolumn = 'Count_ColocalizedGAD_DAPI_Objects'

    def tearDown(self):
        self.dbi.closeconn()

    def test_ProcessInfo(self):
        self.assertNotEqual(self.controller, None)
        for p in self.controller.processes:
            print("Process: ", p, ":", self.controller.processes[p]['caption'])
        self.assertEqual('1. Filter Data',
                         self.controller.processes['process1']['caption'])

    def test_Modules(self):
        self.assertNotEqual(self.controller, None)
        for p in self.controller.cmodules.keys():
            print(p)
            print("Module:", self.controller.cmodules[p][0])
            print("Class:", self.controller.cmodules[p][1])
        self.assertEqual('AutoFilter',
                         self.controller.processes['process1']['classname'])

    def test_ModuleClass(self):
        testprocess = 'process1'
        module_name = self.controller.processes[testprocess]['modulename']
        class_name = self.controller.processes[testprocess]['classname']
        module = importlib.import_module(module_name)
        class_ = getattr(module, class_name)
        mod = class_(self.datafile, self.outputdir)
        self.assertTrue(isinstance(mod, class_))  #class instantiated
        self.assertGreater(len(mod.data), 0)  #data loaded

    def test_RunModuleClass_Simple(self):
        testprocess = 'process1'
        module_name = self.controller.processes[testprocess]['modulename']
        class_name = self.controller.processes[testprocess]['classname']
        module = importlib.import_module(module_name)
        class_ = getattr(module, class_name)
        #Instantiate FilterClass
        mod = class_(self.datafile,
                     self.outputdir,
                     sheet=0,
                     skiprows=0,
                     headers=0)
        # set vars manually
        mod.column = self.testcolumn
        mod.outputallcolumns = True
        mod.minlimit = 20
        mod.maxlimit = 80
        #Run process
        mod.run()

    def test_RunModuleClass_Complex(self):
        testprocess = 'process1'
        module_name = self.controller.processes[testprocess]['modulename']
        class_name = self.controller.processes[testprocess]['classname']
        module = importlib.import_module(module_name)
        class_ = getattr(module, class_name)
        #Instantiate FilterClass
        mod = class_(self.datafile, self.outputdir)
        cfg = mod.getConfigurables()
        for c in cfg.keys():
            print("config: ", c)
            cfg[c] = self.dbi.getConfigByName(self.currentconfig, c)
            print("config set: ", cfg[c])
        mod.setConfigurables(cfg)
        self.assertEqual(mod.column, self.testcolumn)
        mod.run()

    def test_runProcessThread(self):
        testprocess = 'process1'
        type = self.controller.processes[testprocess]['href']
        self.assertEqual(type, 'filter')
        output = self.controller.processes[testprocess]['output']
        processname = self.controller.processes[testprocess]['caption']
        module_name = self.controller.processes[testprocess]['modulename']
        class_name = self.controller.processes[testprocess]['classname']
        config = self.controller.db.getConfig(self.currentconfig)
        # Run Thread
        t = TestThread(self.controller, self.datafile, self.outputdir, output,
                       processname, module_name, class_name, config)
        t.start()
        print("Running Thread - loaded: ", type)