Exemple #1
0
 def __init__(self):
     self.currentconfig = 'default'  # maybe future multiple configs possible
     # connect to db
     self.db = DBI()
     self.db.connect()
     self.logfile = None
     self.logger = self.loadLogger(self.db.userconfigdir)
     self.threadlist=[]
     self._stopevent = threading.Event()
Exemple #2
0
 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, wxObject, configid, processname, processmodule, processclass, outputdir, filename, row):
     """Init Worker Thread Class."""
     threading.Thread.__init__(self)
     self.configID = configid
     self.db = DBI()
     self.max_mem = float(self.db.getConfigByName(self.configID, 'MAX_MEMORY'))
     if self.max_mem is None:
         self.max_mem = 80
     self.wxObject = wxObject
     self.filename = filename
     self.output = outputdir
     # Use outputfile directory rather than filename for progress bar output
     self.outfile = join(self.output, splitext(basename(self.filename))[0])
     self.row = row
     self.processname = processname
     logger = logging.getLogger(processname)
     # Instantiate module
     module = importlib.import_module(processmodule)
     self.class_ = getattr(module, processclass)
     self.mod = self.class_(filename, outputdir)
Exemple #4
0
class ProcessThread(threading.Thread):
    """Multi Worker Thread Class."""

    # ----------------------------------------------------------------------
    def __init__(self, wxObject, configid, processname, processmodule, processclass, outputdir, filename, row):
        """Init Worker Thread Class."""
        threading.Thread.__init__(self)
        self.configID = configid
        self.db = DBI()
        self.max_mem = float(self.db.getConfigByName(self.configID, 'MAX_MEMORY'))
        if self.max_mem is None:
            self.max_mem = 80
        self.wxObject = wxObject
        self.filename = filename
        self.output = outputdir
        # Use outputfile directory rather than filename for progress bar output
        self.outfile = join(self.output, splitext(basename(self.filename))[0])
        self.row = row
        self.processname = processname
        logger = logging.getLogger(processname)
        # Instantiate module
        module = importlib.import_module(processmodule)
        self.class_ = getattr(module, processclass)
        self.mod = self.class_(filename, outputdir)

    def configure(self):
        try:
            # Load all configurable params required for module - get list from module
            cfg = self.mod.getConfigurables()
            self.db.connect()
            for c in cfg.keys():
                cfg[c] = self.db.getConfigByName(self.configID, c)

            self.db.closeconn()
            self.mod.setConfigurables(cfg)

        except Exception as e:
            raise ValueError("Configure:", str(e))
    # ----------------------------------------------------------------------


    def run(self):
        """
        Run module in thread
        :return:
        """
        try:
            # event.set()
            # lock.acquire(True)
            q = dict()
            # Configure parameters
            self.configure()
            logging.info('Configuration set')
            # Run thread processing
            msg = 'Running: %s' % self.filename
            print(msg)
            logging.info(msg)
            if self.mod.imgfile is not None:
                q[self.filename] = self.mod.run()

            else:
                msg = "ERROR: No data loaded for process: %s file: %s" % (self.class_, self.filename)
                print(msg)
                logging.error(msg)
                q[self.filename] = None
                raise ValueError(msg)
            msg = 'Complete: %s' % self.filename
            print(msg)
            logging.info(msg)

        except Exception as e:
            print(e)
            logging.error(e)
            wx.PostEvent(self.wxObject, ResultEvent((-1, self.row, self.processname, self.outfile,e.args[0])))
        finally:
            msg ='Finished ProcessThread'
            print(msg)
            logging.info(msg)
Exemple #5
0
class Controller():
    def __init__(self):
        self.currentconfig = 'default'  # maybe future multiple configs possible
        # connect to db
        self.db = DBI()
        self.db.connect()
        self.logfile = None
        self.logger = self.loadLogger(self.db.userconfigdir)
        self.threadlist=[]
        self._stopevent = threading.Event()

    def loadLogger(self, outputdir=None):
        #### LoggingConfig
        dbug=self.db.getConfigByName(self.currentconfig,'DEBUG')
        if dbug is not None and dbug =='1':
            logger.setLevel(logging.DEBUG)
        else:
            logger.setLevel(logging.INFO)
        # Check dirs exist and are writable
        if outputdir is not None and access(outputdir, R_OK):
            homedir = outputdir
        else:
            userdir = expanduser("~")
            homedir = join(userdir, '.qbi_apps', 'batchcrop')
            if not access(homedir, W_OK):
                if not access(join(userdir, '.qbi_apps'), W_OK):
                    mkdir(join(userdir, '.qbi_apps'))
                mkdir(homedir)

        logdir = join(homedir, "logs")
        if not access(logdir,W_OK):
            mkdir(logdir)
        self.logfile = join(logdir, 'batchcrop.log')
        handler = RotatingFileHandler(filename=self.logfile, maxBytes=10000000, backupCount=10)
        formatter = logging.Formatter(FORMAT)
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        return logger

    def poll(self,t,row,processname,outfile,wxObject,max_mem):
        # Poll thread to update progress bar
        ctr = 0
        increment = 5
        tcount = 90
        while t.is_alive():
            time.sleep(increment)

            # Check CPU usage
            percent = psutil.virtual_memory().percent
            msg = "Controller:RunProcess (t.alive): [%s] %s (%s)" % (
            processname, outfile, "{0}% memory".format(percent))
            print(msg)
            logger.debug(msg)
            if percent > max_mem:
                msg = 'Low memory - stop processing: %d' % percent
                logging.warning(msg)
                print(msg)
                self._stopevent.set()
                raise OSError(msg)

            ctr += increment
            # reset ??
            if ctr == tcount:
                ctr = increment
            # count, row, process, filename
            wx.PostEvent(wxObject, ResultEvent((ctr, row, processname, outfile, "{0}% memory".format(percent))))
            wx.YieldIfNeeded()

    # ----------------------------------------------------------------------
    def RunProcess(self, wxGui, processref, outputdir, filenames,prow):
        """
        :param wxGui:
        :param processref:
        :param outputdir: either set by user or defaults to subdir in input dir (from App.py)
        :param filenames:
        :param row:
        :return:
        """
        self.db.connect()
        processname = self.db.getCaption(processref)
        processmodule = self.db.getProcessModule(processref)
        processclass = self.db.getProcessClass(processref)
        self.db.closeconn()
        # Check users available RAM and CPU
        msg = "CPU count: %d" % psutil.cpu_count(False)
        print(msg)
        logging.info(msg)
        max_mem = float(self.db.getConfigByName(self.currentconfig,'MAX_MEMORY'))
        if max_mem is None:
            max_mem = 80
        avail_mem = psutil.virtual_memory().available
        swap = psutil.swap_memory().free
        percent = psutil.virtual_memory().percent #used/total
        msg = "MEMORY: \n\tAvailable: %d \t Swap: %d \t Percent: %d \n" % (avail_mem,swap,percent)
        print(msg)
        logging.info(msg)
        row = prow
        if len(filenames) > 0:
            # Remove any previous stop
            self._stopevent.clear()
            # One thread per file
            for filename in filenames:
                if not self._stopevent.isSet():
                    msg = "Load Process Threads: %s %s [row: %d]" % (processname, filename, row)
                    print(msg)
                    logger.info(msg)
                    # Outputfile directory rather than filename for progress bar output
                    outfolder = join(outputdir, splitext(basename(filename))[0])
                    # Initial entry
                    wx.PostEvent(wxGui, ResultEvent((0, row, processname, outfolder,'')))
                    wx.YieldIfNeeded()
                    t = ProcessThread(wxGui, self.currentconfig, processname, processmodule, processclass, outputdir,
                                      filename, row)

                    self.threadlist.append(t)
                    t.start()
                    self.poll(t,row,processname,outfolder,wxGui,max_mem)

                    wx.PostEvent(wxGui, ResultEvent((100, row, processname, outfolder,'')))
                    # New row
                    row += 1
                else:
                    msg ='Stop event detected - ending all processing'
                    logging.warning(msg)
                    print(msg)
                    break


        else:
            logger.error("No files to process")
            raise ValueError("No matched files to process")

        return row

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


    def shutdown(self):
        self._stopevent.set()
        msg="Controller: stop event set"
        logging.warning(msg)
        print(msg)
        # Loop through threads to finish?
        for t in self.threadlist:
            if t != threading.main_thread() and t.is_alive():
                msg = 'Stop processing called: closing {0}'.format(t.getName())
                logging.info(msg)
                print(msg)
                t.join(timeout=5)
Exemple #6
0
class TestController(unittest.TestCase):  #TODO: REWRITE FOR SLIDE CROPPER
    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)
 def setUp(self):
     self.dbi = DBI(test=True)
     self.dbi.getconn()
class TestDBquery(unittest.TestCase):
    def setUp(self):
        self.dbi = DBI(test=True)
        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)

    def test_getCaptions(self):
        data = self.dbi.getCaptions()
        expected = 0
        print('Captions: ', data)
        self.assertIsNotNone(data)
        self.assertGreater(len(data), expected)

    def test_getRefs(self):
        data = self.dbi.getRefs()
        expected = 0
        print('Refs: ', data)
        self.assertIsNotNone(data)
        self.assertGreater(len(data), expected)

    def test_getDescription(self):
        ref = 'Crop Slide into Images'
        data = self.dbi.getDescription(ref)
        expected = 0
        print('Description: ', data)
        self.assertIsNotNone(data)
        self.assertGreater(len(data), expected)

    def test_getCaption(self):
        ref = 'crop'
        data = self.dbi.getCaption(ref)
        expected = 0
        print('Caption: ', data)
        self.assertIsNotNone(data)
        self.assertGreater(len(data), expected)

    def test_getProcessModule(self):
        ref = 'crop'
        data = self.dbi.getProcessModule(ref)
        expected = 0
        print('Module: ', data)
        self.assertIsNotNone(data)
        self.assertGreater(len(data), expected)

    def test_getProcessClass(self):
        ref = 'crop'
        data = self.dbi.getProcessClass(ref)
        expected = 0
        print('Class: ', data)
        self.assertIsNotNone(data)
        self.assertGreater(len(data), expected)