Exemple #1
0
    def setUpClass(cls):
        if driver.get_backend_status() in driver.BACKEND_RUNNING:
            microscope = model.getMicroscope()
            if microscope.role != "meteor":
                logging.info(
                    "There is already running backend. It will be turned off, and the backend of METEOR will be turned on."
                )
                test.stop_backend()
                test.start_backend(METEOR_CONFIG)
            else:
                logging.info(
                    "There is METEOR backend already running. It will be used."
                )
        else:
            try:
                logging.info("METEOR backend will be turned on.")
                test.start_backend(METEOR_CONFIG)
            except Exception:
                raise

        # get the stage components
        cls.stage = model.getComponent(role="stage-bare")

        # get the metadata
        stage_md = cls.stage.getMetadata()
        cls.stage_grid_centers = stage_md[model.MD_SAMPLE_CENTERS]
        cls.stage_loading = stage_md[model.MD_FAV_POS_DEACTIVE]
Exemple #2
0
    def setUpClass(cls):
        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SPARC_CONFIG]
        ret = subprocess.call(cmd)
        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)
        time.sleep(1) # time to start

        # Find CCD & SEM components
        cls.microscope = model.getMicroscope()
        for comp in model.getComponents():
            if comp.role == "ccd":
                cls.ccd = comp
            elif comp.role == "spectrometer":
                cls.spec = comp
            elif comp.role == "e-beam":
                cls.ebeam = comp
            elif comp.role == "se-detector":
                cls.sed = comp
            elif comp.role == "light":
                cls.light = comp
            elif comp.role == "filter":
                cls.light_filter = comp
Exemple #3
0
    def setUpClass(cls):
        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SPARC_CONFIG]
        ret = subprocess.call(cmd)
        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)
        time.sleep(1) # time to start

        # Find CCD & SEM components
        cls.microscope = model.getMicroscope()
        for comp in model.getComponents():
            if comp.role == "ccd":
                cls.ccd = comp
            elif comp.role == "spectrometer":
                cls.spec = comp
            elif comp.role == "e-beam":
                cls.ebeam = comp
            elif comp.role == "se-detector":
                cls.sed = comp
Exemple #4
0
def stop_backend():
    """
    Stop the backend and wait for it to be fully stopped
    """
    cmd = ODEMISD_CMD + ["--kill"]
    ret = subprocess.call(cmd)
    if ret != 0:
        raise IOError("Failed stopping backend with '%s' (returned %d)" % (cmd, ret))

    # wait for the backend to be fully stopped
    time.sleep(1) # time to stop
    end = time.time() + 15 # s timeout
    while time.time() < end:
        status = driver.get_backend_status()
        if status in (driver.BACKEND_RUNNING, driver.BACKEND_STARTING):
            logging.info("Backend is stopping...")
            time.sleep(1)
        else:
            break
    else:
        raise IOError("Backend still stopping after 15 s")

    model._core._microscope = None # force reset of the microscope for next connection

    if status != driver.BACKEND_STOPPED:
        raise IOError("Backend failed to stop, now %s" % status)
Exemple #5
0
    def setUpClass(cls):

        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_LENS_CONFIG]
        ret = subprocess.call(cmd)
        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)
        time.sleep(1)  # time to start

        # find components by their role
        cls.ebeam = model.getComponent(role="e-beam")
        cls.sed = model.getComponent(role="bs-detector")
        cls.ccd = model.getComponent(role="ccd")
        cls.sem_stage = model.getComponent(role="sem-stage")
        cls.opt_stage = model.getComponent(role="align")
        cls.ebeam_focus = model.getComponent(role="ebeam-focus")
        cls.focus = model.getComponent(role="focus")
        cls.light = model.getComponent(role="light")
        cls.light_filter = model.getComponent(role="filter")
        cls.combined_stage = model.getComponent(role="stage")
Exemple #6
0
def start_backend(config):
    """
    Start the backend by checking the currently running backend. Basically 2 cases/scenarios:
        1. If no running backend => run the requested one.
        2. If there is running backend =>
            a. If the running backend is same as requested one => do nothing
            b. If the running backend is different from the requested one => stop the running, and run the requested one.
    In case the backend fails to start a IOError will be raised.
    config (str): path to the microscope config file.
    """
    # check if a backend is running
    if driver.get_backend_status() in (driver.BACKEND_RUNNING,
                                       driver.BACKEND_STARTING):
        current_model = model.getMicroscope().model
        try:
            req_model = modelgen.Instantiator(open(config)).ast
        except Exception as exp:
            raise ValueError(exp)
        if current_model == req_model:
            logging.info("Backend for %s already running", config)
            return
        else:
            logging.info(
                "There is a backend running already, it will be turned off, and the backend \
                                %s will be run instead.", config)
            stop_backend()
            run_backend(config)

    # check if no backend is running
    else:
        run_backend(config)
Exemple #7
0
    def setUpClass(cls):
        try:
            import fastem_calibrations
        except ImportError as err:
            raise unittest.SkipTest(
                f"Skipping the fastem tests, correct libraries "
                f"to perform the tests are not available.\n"
                f"Got the error: {err}")

        if TEST_NOHW:
            test.start_backend(FASTEM_CONFIG)
        elif driver.get_backend_status() != driver.BACKEND_RUNNING:
            raise IOError(
                "Backend controlling a real hardware should be started before running this test case"
            )

        # get the hardware components
        cls.scanner = model.getComponent(role='e-beam')
        cls.asm = model.getComponent(role="asm")
        cls.mppc = model.getComponent(role="mppc")
        cls.multibeam = model.getComponent(role="multibeam")
        cls.descanner = model.getComponent(role="descanner")
        cls.stage = model.getComponent(
            role="stage"
        )  # TODO replace with stage-scan when ROA conversion method available
        cls.ccd = model.getComponent(role="diagnostic-ccd")
        cls.beamshift = model.getComponent(role="ebeam-shift")
        cls.det_rotator = model.getComponent(role="det-rotator")
Exemple #8
0
def stop_backend():
    """
    Stop the backend and wait for it to be fully stopped
    """
    cmd = ODEMISD_CMD + ["--kill"]
    ret = subprocess.call(cmd)
    if ret != 0:
        raise IOError("Failed stopping backend with '%s' (returned %d)" % (cmd, ret))

    # wait for the backend to be fully stopped
    time.sleep(1) # time to stop
    end = time.time() + 15 # s timeout
    while time.time() < end:
        status = driver.get_backend_status()
        if status in (driver.BACKEND_RUNNING, driver.BACKEND_STARTING):
            logging.info("Backend is stopping...")
            time.sleep(1)
        else:
            break
    else:
        raise IOError("Backend still stopping after 15 s")

    model._core._microscope = None # force reset of the microscope for next connection

    if status != driver.BACKEND_STOPPED:
        raise IOError("Backend failed to stop, now %s" % status)
Exemple #9
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """
    # arguments handling
    parser = argparse.ArgumentParser()
    parser.add_argument("--role", dest="role", metavar="<component>",
                        help="display and update an image on the screen")
    parser.add_argument("--gridsize", dest="gridsize", nargs=2, metavar="<gridsize>", type=int, default=None,
                        help="size of the grid of spots in x y, default 14 14")
    parser.add_argument("--log-level", dest="loglev", metavar="<level>", type=int, choices=[0, 1, 2],
                        default=0, help="set verbosity level (0-2, default = 0)")
    options = parser.parse_args(args[1:])
    # Set up logging before everything else
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # change the log format to be more descriptive
    handler = logging.StreamHandler()
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(logging.Formatter('%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    if options.role:
        if get_backend_status() != BACKEND_RUNNING:
            raise ValueError("Backend is not running while role command is specified.")
        ccd = model.getComponent(role=options.role)
        live_display(ccd, ccd.data, kill_ccd=False, gridsize=options.gridsize)
    else:
        ccd = ueye.Camera("camera", "ccd", device=None)
        ccd.SetFrameRate(2)
        live_display(ccd, ccd.data, gridsize=options.gridsize)
    return 0
def main(args):
    """
    Handles the command line arguments.

    Parameters
    ----------
    args: The list of arguments passed.

    Returns
    -------
    (int)
        value to return to the OS as program exit code.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('--debug', action="store_true", default=False)
    parser.add_argument("--role", dest="role", default="diagnostic-ccd",
                        metavar="<component>",
                        help="Role of the camera to connect to via the Odemis "
                             "back-end. Ex: 'ccd'.")
    parser.add_argument("--channel", dest="channel", default=1,
                        metavar="<component>",
                        help="Number of the AWG output channel.")
    parser.add_argument("--auto", dest="auto", default=True,
                        metavar="<component>",
                        help="If True automatically align the ebeam scan to"
                             "multiprobe. To do this a server must be running "
                             "on the microscope PC.")

    options = parser.parse_args(args[1:])
    if options.debug:
        logging.getLogger().setLevel(logging.DEBUG)
    else:
        logging.getLogger().setLevel(logging.WARNING)

    if get_backend_status() != BACKEND_RUNNING:
        raise ValueError("Backend is not running.")

    ccd = model.getComponent(role=options.role)
    try:
        sem_rotation = get_sem_rotation(ccd, auto=options.auto,
                                        channel=options.channel)
        if options.auto:
            scanner = model.getComponent(role="ebeam-control")
            val = scanner.rotation.value
            scanner.rotation.value = val + sem_rotation
            print("Added {:.2f}° to the scan rotation using SEM PC."
                  "Rotation is now set to: {:.2f}°".format(
                math.degrees(sem_rotation),
                math.degrees(scanner.rotation.value)))
        else:
            print("Add {:.2f}° to the scan rotation using SEM PC. If negative"
                  "subtract this value from the scan rotation.".format(
                math.degrees(sem_rotation)))
    except Exception as exp:
        logging.error("%s", exp, exc_info=True)
        return 128
    return 0
Exemple #11
0
 def test_no_running_backend(self):
     # check if there is no running backend
     backend_status = driver.get_backend_status()
     self.assertIn(backend_status,
                   [driver.BACKEND_STOPPED, driver.BACKEND_DEAD])
     # run enzel
     test.start_backend(ENZEL_CONFIG)
     # now check if the role is enzel
     role = model.getMicroscope().role
     self.assertEqual(role, "enzel")
Exemple #12
0
    def setUpClass(cls):
        if TEST_NOHW:
            test.start_backend(FASTEM_CONFIG)
        elif driver.get_backend_status() != driver.BACKEND_RUNNING:
            raise IOError("Backend controlling a real hardware should be started before running this test case")

        cls.ebeam = model.getComponent(role="e-beam")
        cls.efocuser = model.getComponent(role="ebeam-focus")
        cls.sed = model.getComponent(role="se-detector")
        cls.stage = model.getComponent(role="stage")
        cls.stage.reference({"x", "y"}).result()
Exemple #13
0
    def setUpClass(cls):
        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_CONFIG]
        ret = subprocess.call(cmd)
        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)
        time.sleep(1) # time to start
Exemple #14
0
def run_backend(config):
    """
    Run the backend based on the passed config yaml file.
    config (str): path to the microscope config file
    raises:
        LookupError: if a backend is already running
        IOError: if backend failed to start
    """
    if driver.get_backend_status() in (driver.BACKEND_RUNNING,
                                       driver.BACKEND_STARTING):
        raise LookupError("A running backend is already found")

    logging.info("Starting backend with config file '%s'", config)

    # run the backend as a daemon
    # we cannot run it normally as the child would also think he's in a unittest
    cmd = ODEMISD_CMD + ODEMISD_ARG + [config]
    ret = subprocess.call(cmd, preexec_fn=setlimits)
    if ret != 0:
        raise IOError("Failed starting backend with '%s' (returned %d)" %
                      (cmd, ret))

    time.sleep(3)  # give some time to the backend to start a little bit

    timeout = 30  # s timeout
    end = time.time() + timeout
    while time.time() < end:
        status = driver.get_backend_status()
        if status == driver.BACKEND_STARTING:
            logging.info("Backend is starting...")
            time.sleep(1)
        else:
            break
    else:
        raise IOError("Backend still starting after %d s" % (timeout, ))

    if status != driver.BACKEND_RUNNING:
        raise IOError("Backend failed to start, now %s" % status)
Exemple #15
0
    def setUp(self):
        # reset the logging (because otherwise it accumulates)
        if logging.root:
            del logging.root.handlers[:]

        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            self.skipTest("Running backend found")

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_CONFIG]
        ret = subprocess.call(cmd)
        self.assertEqual(ret, 0, "trying to run '%s'" % cmd)
        time.sleep(1)  # time to start
Exemple #16
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """
    # arguments handling
    parser = argparse.ArgumentParser()
    parser.add_argument("--role",
                        dest="role",
                        metavar="<component>",
                        help="display and update an image on the screen")
    parser.add_argument("--gridsize",
                        dest="gridsize",
                        nargs=2,
                        metavar="<gridsize>",
                        type=int,
                        default=None,
                        help="size of the grid of spots in x y, default 14 14")
    parser.add_argument("--log-level",
                        dest="loglev",
                        metavar="<level>",
                        type=int,
                        choices=[0, 1, 2],
                        default=0,
                        help="set verbosity level (0-2, default = 0)")
    options = parser.parse_args(args[1:])
    # Set up logging before everything else
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # change the log format to be more descriptive
    handler = logging.StreamHandler()
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(
        logging.Formatter(
            '%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    if options.role:
        if get_backend_status() != BACKEND_RUNNING:
            raise ValueError(
                "Backend is not running while role command is specified.")
        ccd = model.getComponent(role=options.role)
        live_display(ccd, ccd.data, kill_ccd=False, gridsize=options.gridsize)
    else:
        ccd = ueye.Camera("camera", "ccd", device=None)
        ccd.SetFrameRate(2)
        live_display(ccd, ccd.data, gridsize=options.gridsize)
    return 0
Exemple #17
0
    def setUp(self):
        # reset the logging (because otherwise it accumulates)
        if logging.root:
            del logging.root.handlers[:]
            
        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            self.skipTest("Running backend found")

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_CONFIG]
        ret = subprocess.call(cmd)
        self.assertEqual(ret, 0, "trying to run '%s'" % cmd)
        time.sleep(1) # time to start
Exemple #18
0
    def setUpClass(cls):
        if TEST_NOHW:
            test.start_backend(FASTEM_CONFIG_ASM)
        elif driver.get_backend_status() != driver.BACKEND_RUNNING:
            raise IOError("Backend controlling a real hardware should be started before running this test case")

        # get the hardware components
        cls.asm = model.getComponent(role="asm")
        cls.mppc = model.getComponent(role="mppc")
        cls.multibeam = model.getComponent(role="multibeam")
        cls.descanner = model.getComponent(role="descanner")
        cls.stage = model.getComponent(
            role="stage")  # TODO replace with stage-scan when ROA conversion method available
        cls.stage.reference({"x", "y"}).result()
Exemple #19
0
def start_backend(config):
    """
    Start the backend
    config (str): path to the microscope config file
    raises:
        LookupError: if a backend is already running
        IOError: if backend failed to start
    """
    if driver.get_backend_status() in (driver.BACKEND_RUNNING, driver.BACKEND_STARTING):
        raise LookupError("A running backend is already found")

    logging.info("Starting backend with config file '%s'", config)

    # run the backend as a daemon
    # we cannot run it normally as the child would also think he's in a unittest
    cmd = ODEMISD_CMD + ODEMISD_ARG + [config]
    ret = subprocess.call(cmd, preexec_fn=setlimits)
    if ret != 0:
        raise IOError("Failed starting backend with '%s' (returned %d)" % (cmd, ret))

    time.sleep(3)  # give some time to the backend to start a little bit

    timeout = 30  # s timeout
    end = time.time() + timeout
    while time.time() < end:
        status = driver.get_backend_status()
        if status == driver.BACKEND_STARTING:
            logging.info("Backend is starting...")
            time.sleep(1)
        else:
            break
    else:
        raise IOError("Backend still starting after %d s" % (timeout,))

    if status != driver.BACKEND_RUNNING:
        raise IOError("Backend failed to start, now %s" % status)
Exemple #20
0
    def test_speedUpPyroConnect(self):
        need_stop = False
        if driver.get_backend_status() != driver.BACKEND_RUNNING:
            need_stop = True
            cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_CONFIG]
            ret = subprocess.call(cmd)
            if ret != 0:
                logging.error("Failed starting backend with '%s'", cmd)
            time.sleep(1) # time to start
        else:
            model._components._microscope = None # force reset of the microscope for next connection

        speedUpPyroConnect(model.getMicroscope())

        if need_stop:
            cmd = ODEMISD_CMD + ["--kill"]
            subprocess.call(cmd)
Exemple #21
0
    def setUpClass(cls):
        if TEST_NOHW:
            test.start_backend(FASTEM_CONFIG_ASM)
        elif driver.get_backend_status() != driver.BACKEND_RUNNING:
            raise IOError("Backend controlling a real hardware should be started before running this test case")

        # Get the hardware components from the simulators or hardware
        cls.scanner = model.getComponent(role='e-beam')
        cls.asm = model.getComponent(role="asm")
        cls.mppc = model.getComponent(role="mppc")
        cls.multibeam = model.getComponent(role="multibeam")
        cls.descanner = model.getComponent(role="descanner")
        cls.stage = model.getComponent(
            role="stage")  # TODO replace with stage-scan when ROA conversion method available
        cls.ccd = model.getComponent(role="diagnostic-ccd")
        cls.beamshift = model.getComponent(role="ebeam-shift")
        cls.lens = model.getComponent(role="lens")

        cls.beamshift.shift.value = (0, 0)
        cls.stage.reference({"x", "y"}).result()
    def setUpClass(cls):

        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_LENS_CONFIG]
        ret = subprocess.call(cmd)
        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)
        time.sleep(1) # time to start

        # find components by their role
        cls.ebeam = model.getComponent(role="e-beam")
        cls.sed = model.getComponent(role="se-detector")
        cls.ccd = model.getComponent(role="ccd")
        cls.light = model.getComponent(role="light")
        cls.light_filter = model.getComponent(role="filter")
Exemple #23
0
    def setUpClass(cls):

        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_CONFIG]
        ret = subprocess.call(cmd)
        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)
        time.sleep(1) # time to start

        # create some streams connected to the backend
        cls.microscope = model.getMicroscope()
        for comp in model.getComponents():
            if comp.role == "ccd":
                cls.ccd = comp
            elif comp.role == "spectrometer":
                cls.spec = comp
            elif comp.role == "e-beam":
                cls.ebeam = comp
            elif comp.role == "se-detector":
                cls.sed = comp
            elif comp.role == "light":
                cls.light = comp
            elif comp.role == "filter":
                cls.light_filter = comp

        s1 = stream.FluoStream("fluo1", cls.ccd, cls.ccd.data,
                               cls.light, cls.light_filter)
        s2 = stream.FluoStream("fluo2", cls.ccd, cls.ccd.data,
                               cls.light, cls.light_filter)
        s2.excitation.value = s2.excitation.range[1]
        s3 = stream.BrightfieldStream("bf", cls.ccd, cls.ccd.data, cls.light)
        cls.streams = [s1, s2, s3]
Exemple #24
0
    def setUpClass(cls):
        if TEST_NOHW:
            test.start_backend(FASTEM_CONFIG_ASM)
        elif driver.get_backend_status() != driver.BACKEND_RUNNING:
            raise IOError("Backend controlling a real hardware should be started before running this test case")

        # get the hardware components
        cls.scanner = model.getComponent(role='e-beam')
        cls.asm = model.getComponent(role="asm")
        cls.mppc = model.getComponent(role="mppc")
        cls.multibeam = model.getComponent(role="multibeam")
        cls.descanner = model.getComponent(role="descanner")
        cls.stage = model.getComponent(
            role="stage")  # TODO replace with stage-scan when ROA conversion method available
        cls.ccd = model.getComponent(role="diagnostic-ccd")
        cls.beamshift = model.getComponent(role="ebeam-shift")
        cls.lens = model.getComponent(role="lens")

        # Normally the beamshift MD_CALIB is set when running the calibrations.
        # Set it here explicitly because we do not run the calibrations in these test cases.
        cls.beamshift.updateMetadata({model.MD_CALIB: cls.scanner.beamShiftTransformationMatrix.value})
        cls.beamshift.shift.value = (0, 0)
        cls.stage.reference({"x", "y"}).result()
Exemple #25
0
    def setUpClass(cls):

        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_LENS_CONFIG]
        # FIXME: give an informative warning when the comedi module has not been loaded
        ret = subprocess.call(cmd)

        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)

        time.sleep(1)  # time to start

        # find components by their role
        cls.stage = model.getComponent(role="stage")
        cls.sem_stage = model.getComponent(role="sem-stage")
        cls.align = model.getComponent(role="align")
        cls.tmcm = model.getComponent(name="TMCM")  # low level actuator
Exemple #26
0
    def setUpClass(cls):

        if driver.get_backend_status() == driver.BACKEND_RUNNING:
            logging.info("A running backend is already found, skipping tests")
            cls.backend_was_running = True
            return

        # run the backend as a daemon
        # we cannot run it normally as the child would also think he's in a unittest
        cmd = ODEMISD_CMD + ODEMISD_ARG + [SECOM_LENS_CONFIG]
        # FIXME: give an informative warning when the comedi module has not been loaded
        ret = subprocess.call(cmd)

        if ret != 0:
            logging.error("Failed starting backend with '%s'", cmd)

        time.sleep(1)  # time to start

        # find components by their role
        cls.stage = model.getComponent(role="stage")
        cls.sem_stage = model.getComponent(role="sem-stage")
        cls.align = model.getComponent(role="align")
        cls.tmcm = model.getComponent(name="TMCM") # low level actuator
Exemple #27
0
 def setUpClass(cls):
     # make sure initially no backend is running.
     if driver.get_backend_status() == driver.BACKEND_RUNNING:
         test.stop_backend()
Exemple #28
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    # arguments handling
    parser = argparse.ArgumentParser(prog="odemis-cli",
                                     description=odemis.__fullname__)

    parser.add_argument('--version',
                        dest="version",
                        action='store_true',
                        help="show program's version number and exit")
    opt_grp = parser.add_argument_group('Options')
    opt_grp.add_argument("--log-level",
                         dest="loglev",
                         metavar="<level>",
                         type=int,
                         default=0,
                         help="set verbosity level (0-2, default = 0)")
    opt_grp.add_argument(
        "--machine",
        dest="machine",
        action="store_true",
        default=False,
        help="display in a machine-friendly way (i.e., no pretty printing)")
    dm_grp = parser.add_argument_group('Microscope management')
    dm_grpe = dm_grp.add_mutually_exclusive_group()
    dm_grpe.add_argument("--kill",
                         "-k",
                         dest="kill",
                         action="store_true",
                         default=False,
                         help="kill the running back-end")
    dm_grpe.add_argument(
        "--check",
        dest="check",
        action="store_true",
        default=False,
        help="check for a running back-end (only returns exit code)")
    dm_grpe.add_argument(
        "--scan",
        dest="scan",
        action="store_true",
        default=False,
        help=
        "scan for possible devices to connect (the back-end must be stopped)")
    dm_grpe.add_argument("--list",
                         "-l",
                         dest="list",
                         action="store_true",
                         default=False,
                         help="list the components of the microscope")
    dm_grpe.add_argument("--list-prop",
                         "-L",
                         dest="listprop",
                         metavar="<component>",
                         help="list the properties of a component")
    dm_grpe.add_argument(
        "--set-attr",
        "-s",
        dest="setattr",
        nargs=3,
        action='append',
        metavar=("<component>", "<attribute>", "<value>"),
        help="set the attribute of a component (lists are delimited by commas,"
        " dictionary keys are delimited by colon)")
    dm_grpe.add_argument("--move",
                         "-m",
                         dest="move",
                         nargs=3,
                         action='append',
                         metavar=("<component>", "<axis>", "<distance>"),
                         help=u"move the axis by the amount of µm.")
    dm_grpe.add_argument("--position",
                         "-p",
                         dest="position",
                         nargs=3,
                         action='append',
                         metavar=("<component>", "<axis>", "<position>"),
                         help=u"move the axis to the given position in µm.")
    dm_grpe.add_argument(
        "--stop",
        "-S",
        dest="stop",
        action="store_true",
        default=False,
        help="immediately stop all the actuators in all directions.")
    dm_grpe.add_argument(
        "--acquire",
        "-a",
        dest="acquire",
        nargs="+",
        metavar=("<component>", "data-flow"),
        help="acquire an image (default data-flow is \"data\")")
    dm_grp.add_argument(
        "--output",
        "-o",
        dest="output",
        help=
        "name of the file where the image should be saved after acquisition. The file format is derived from the extension (TIFF and HDF5 are supported)."
    )
    dm_grpe.add_argument(
        "--live",
        dest="live",
        nargs="+",
        metavar=("<component>", "data-flow"),
        help=
        "display and update an image on the screen (default data-flow is \"data\")"
    )

    options = parser.parse_args(args[1:])

    # To allow printing unicode even with pipes
    ensure_output_encoding()

    # Cannot use the internal feature, because it doesn't support multiline
    if options.version:
        print(odemis.__fullname__ + " " + odemis.__version__ + "\n" +
              odemis.__copyright__ + "\n" + "Licensed under the " +
              odemis.__license__)
        return 0

    # Set up logging before everything else
    if options.loglev < 0:
        parser.error("log-level must be positive.")
    # TODO: allow to put logging level so low that nothing is ever output
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # change the log format to be more descriptive
    handler = logging.StreamHandler()
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(
        logging.Formatter(
            '%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    # anything to do?
    if (not options.check and not options.kill and not options.scan
            and not options.list and not options.stop and options.move is None
            and options.position is None and options.listprop is None
            and options.setattr is None and options.acquire is None
            and options.live is None):
        logging.error("no action specified.")
        return 127
    if options.acquire is not None and options.output is None:
        logging.error("name of the output file must be specified.")
        return 127

    logging.debug("Trying to find the backend")
    status = get_backend_status()
    if options.check:
        logging.info("Status of back-end is %s", status)
        return status_to_xtcode[status]

    # scan needs to have the backend stopped
    if options.scan:
        if status == BACKEND_RUNNING:
            logging.error("Back-end running while trying to scan for devices")
            return 127
        try:
            return scan()
        except Exception:
            logging.exception("Unexpected error while performing scan.")
            return 127

    # check if there is already a backend running
    if status == BACKEND_STOPPED:
        logging.error("No running back-end")
        return 127
    elif status == BACKEND_DEAD:
        logging.error("Back-end appears to be non-responsive.")
        return 127

    try:
        if options.kill:
            return kill_backend()

        logging.debug("Executing the actions")

        if options.list:
            return list_components(pretty=not options.machine)
        elif options.listprop is not None:
            # Speed up is only worthy if many VAs are accessed
            odemis.util.driver.speedUpPyroConnect(model.getMicroscope())
            return list_properties(options.listprop,
                                   pretty=not options.machine)
        elif options.setattr is not None:
            for c, a, v in options.setattr:
                ret = set_attr(c, a, v)
                if ret != 0:
                    return ret
        elif options.position is not None:
            for c, a, d in options.position:
                ret = move_abs(c, a, d)
                # TODO warn if same axis multiple times
                if ret != 0:
                    return ret
            time.sleep(0.5)
        elif options.move is not None:
            for c, a, d in options.move:
                ret = move(c, a, d)
                # TODO move commands to the same actuator should be agglomerated
                if ret != 0:
                    return ret
            time.sleep(0.5)  # wait a bit for the futures to close nicely
        elif options.stop:
            return stop_move()
        elif options.acquire is not None:
            component = options.acquire[0]
            if len(options.acquire) == 1:
                dataflows = ["data"]
            else:
                dataflows = options.acquire[1:]
            filename = options.output.decode(sys.getfilesystemencoding())
            return acquire(component, dataflows, filename)
        elif options.live is not None:
            component = options.live[0]
            if len(options.live) == 1:
                dataflow = "data"
            elif len(options.live) == 2:
                dataflow = options.acquire[2]
            else:
                logging.error("live command accepts only one data-flow")
                return 127
            return live_display(component, dataflow)
    except:
        logging.exception("Unexpected error while performing action.")
        return 127

    return 0
Exemple #29
0
def main(args):
    """
    Contains the console handling code for the daemon
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    #print args
    # arguments handling
    parser = argparse.ArgumentParser(description=odemis.__fullname__)

    parser.add_argument('--version',
                        dest="version",
                        action='store_true',
                        help="show program's version number and exit")
    dm_grp = parser.add_argument_group('Daemon management')
    dm_grpe = dm_grp.add_mutually_exclusive_group()
    dm_grpe.add_argument("--kill",
                         "-k",
                         dest="kill",
                         action="store_true",
                         default=False,
                         help="Kill the running back-end")
    dm_grpe.add_argument(
        "--check",
        dest="check",
        action="store_true",
        default=False,
        help="Check for a running back-end (only returns exit code)")
    dm_grpe.add_argument("--daemonize",
                         "-D",
                         action="store_true",
                         dest="daemon",
                         default=False,
                         help="Daemonize the back-end")
    opt_grp = parser.add_argument_group('Options')
    opt_grp.add_argument(
        '--validate',
        dest="validate",
        action="store_true",
        default=False,
        help="Validate the microscope description file and exit")
    dm_grpe.add_argument(
        "--debug",
        action="store_true",
        dest="debug",
        default=False,
        help="Activate debug mode, where everything runs in one process")
    opt_grp.add_argument("--log-level",
                         dest="loglev",
                         metavar="LEVEL",
                         type=int,
                         default=0,
                         help="Set verbosity level (0-2, default = 0)")
    opt_grp.add_argument(
        "--log-target",
        dest="logtarget",
        metavar="{auto,stderr,filename}",
        default="auto",
        help="Specify the log target (auto, stderr, filename)")
    # The settings file is opened here because root privileges are dropped at some point after
    # the initialization.
    opt_grp.add_argument(
        "--settings",
        dest='settings',
        type=argparse.FileType('a+'),
        help="Path to the settings file "
        "(stores values of persistent properties and metadata). "
        "Default is %s, if writable." % DEFAULT_SETTINGS_FILE)
    parser.add_argument(
        "model",
        metavar="file.odm.yaml",
        nargs='?',
        type=open,
        help="Microscope model instantiation file (*.odm.yaml)")

    options = parser.parse_args(args[1:])

    # Cannot use the internal feature, because it doesn't support multiline
    if options.version:
        print(odemis.__fullname__ + " " + odemis.__version__ + "\n" +
              odemis.__copyright__ + "\n" + "Licensed under the " +
              odemis.__license__)
        return 0

    # Set up logging before everything else
    if options.loglev < 0:
        parser.error("log-level must be positive.")
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # auto = {odemis.log if daemon, stderr otherwise}
    if options.logtarget == "auto":
        # default to SysLogHandler ?
        if options.daemon:
            options.logtarget = "odemis.log"
        else:
            options.logtarget = "stderr"
    if options.logtarget == "stderr":
        handler = logging.StreamHandler()
    else:
        if sys.platform.startswith('linux'):
            # On Linux, we use logrotate, so nothing much to do
            handler = WatchedFileHandler(options.logtarget)
        else:
            # Rotate the log, with max 5*50Mb used.
            # Note: we used to rely on RotatingFileHandler, but due to multi-
            # processes, it would be rotated multiple times every time it reached the
            # limit. So now, just do it at startup, and hope it doesn't reach huge
            # size in one run.
            rotateLog(options.logtarget, maxBytes=50 * (2**20), backupCount=5)
            handler = FileHandler(options.logtarget)
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(
        logging.Formatter(
            "%(asctime)s\t%(levelname)s\t%(module)s:%(lineno)d:\t%(message)s"))
    logging.getLogger().addHandler(handler)

    if loglev <= logging.DEBUG:
        # Activate also Pyro logging
        # TODO: options.logtarget
        pyrolog = logging.getLogger("Pyro4")
        pyrolog.setLevel(min(pyrolog.getEffectiveLevel(), logging.INFO))

    # Useful to debug cases of multiple conflicting installations
    logging.info("Starting Odemis back-end v%s (from %s) using Python %d.%d",
                 odemis.__version__, __file__, sys.version_info[0],
                 sys.version_info[1])

    if options.validate and (options.kill or options.check or options.daemon):
        logging.error(
            "Impossible to validate a model and manage the daemon simultaneously"
        )
        return 1

    # Daemon management
    # python-daemon is a fancy library but seems to do too many things for us.
    # We just need to contact the backend and see what happens
    status = get_backend_status()
    if options.check:
        logging.info("Status of back-end is %s", status)
        return status_to_xtcode[status]

    try:
        if options.kill:
            if status != BACKEND_RUNNING:
                raise IOError("No running back-end to kill")
            backend = model.getContainer(model.BACKEND_NAME)
            backend.terminate()
            return 0

        # check if there is already a backend running
        if status == BACKEND_RUNNING:
            raise IOError("Back-end already running, cannot start a new one")

        if options.model is None:
            raise ValueError("No microscope model instantiation file provided")

        if options.settings is None:
            try:
                options.settings = open(DEFAULT_SETTINGS_FILE, "r+")
            except IOError as ex:
                logging.warning("%s. Will not be able to use persistent data",
                                ex)

        if options.debug:
            cont_pol = BackendRunner.CONTAINER_ALL_IN_ONE
        else:
            cont_pol = BackendRunner.CONTAINER_SEPARATED

        # let's become the back-end for real
        runner = BackendRunner(options.model,
                               options.settings,
                               options.daemon,
                               dry_run=options.validate,
                               containement=cont_pol)
        runner.run()
    except ValueError as exp:
        logging.error("%s", exp)
        return 127
    except IOError as exp:
        logging.error("%s", exp)
        return 129
    except Exception:
        logging.exception("Unexpected error while performing action.")
        return 130

    return 0
Exemple #30
0
def main(args):
    """
    Contains the console handling code for the daemon
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    #print args
    # arguments handling
    parser = argparse.ArgumentParser(description=odemis.__fullname__)

    parser.add_argument('--version', dest="version", action='store_true',
                        help="show program's version number and exit")
    dm_grp = parser.add_argument_group('Daemon management')
    dm_grpe = dm_grp.add_mutually_exclusive_group()
    dm_grpe.add_argument("--kill", "-k", dest="kill", action="store_true", default=False,
                         help="Kill the running back-end")
    dm_grpe.add_argument("--check", dest="check", action="store_true", default=False,
                         help="Check for a running back-end (only returns exit code)")
    dm_grpe.add_argument("--daemonize", "-D", action="store_true", dest="daemon",
                         default=False, help="Daemonize the back-end")
    opt_grp = parser.add_argument_group('Options')
    opt_grp.add_argument('--validate', dest="validate", action="store_true", default=False,
                         help="Validate the microscope description file and exit")
    dm_grpe.add_argument("--debug", action="store_true", dest="debug",
                         default=False, help="Activate debug mode, where everything runs in one process")
    opt_grp.add_argument("--log-level", dest="loglev", metavar="LEVEL", type=int,
                         default=0, help="Set verbosity level (0-2, default = 0)")
    opt_grp.add_argument("--log-target", dest="logtarget", metavar="{auto,stderr,filename}",
                         default="auto", help="Specify the log target (auto, stderr, filename)")
    # The settings file is opened here because root privileges are dropped at some point after
    # the initialization.
    opt_grp.add_argument("--settings", dest='settings',
                         type=argparse.FileType('a+'), help="Path to the settings file "
                         "(stores values of persistent properties and metadata). "
                         "Default is %s, if writable." % DEFAULT_SETTINGS_FILE)
    parser.add_argument("model", metavar="file.odm.yaml", nargs='?', type=open,
                        help="Microscope model instantiation file (*.odm.yaml)")

    options = parser.parse_args(args[1:])

    # Cannot use the internal feature, because it doesn't support multiline
    if options.version:
        print(odemis.__fullname__ + " " + odemis.__version__ + "\n" +
              odemis.__copyright__ + "\n" +
              "Licensed under the " + odemis.__license__)
        return 0

    # Set up logging before everything else
    if options.loglev < 0:
        parser.error("log-level must be positive.")
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # auto = {odemis.log if daemon, stderr otherwise}
    if options.logtarget == "auto":
        # default to SysLogHandler ?
        if options.daemon:
            options.logtarget = "odemis.log"
        else:
            options.logtarget = "stderr"
    if options.logtarget == "stderr":
        handler = logging.StreamHandler()
    else:
        if os.sys.platform.startswith('linux'):
            # On Linux, we use logrotate, so nothing much to do
            handler = WatchedFileHandler(options.logtarget)
        else:
            # Rotate the log, with max 5*50Mb used.
            # Note: we used to rely on RotatingFileHandler, but due to multi-
            # processes, it would be rotated multiple times every time it reached the
            # limit. So now, just do it at startup, and hope it doesn't reach huge
            # size in one run.
            rotateLog(options.logtarget, maxBytes=50 * (2 ** 20), backupCount=5)
            handler = FileHandler(options.logtarget)
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(logging.Formatter('%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    if loglev <= logging.DEBUG:
        # Activate also Pyro logging
        # TODO: options.logtarget
        pyrolog = logging.getLogger("Pyro4")
        pyrolog.setLevel(min(pyrolog.getEffectiveLevel(), logging.INFO))

    # Useful to debug cases of multiple conflicting installations
    logging.info("Starting Odemis back-end v%s (from %s)", odemis.__version__, __file__)

    if options.validate and (options.kill or options.check or options.daemon):
        logging.error("Impossible to validate a model and manage the daemon simultaneously")
        return 1

    # Daemon management
    # python-daemon is a fancy library but seems to do too many things for us.
    # We just need to contact the backend and see what happens
    status = get_backend_status()
    if options.check:
        logging.info("Status of back-end is %s", status)
        return status_to_xtcode[status]

    try:
        if options.kill:
            if status != BACKEND_RUNNING:
                raise IOError("No running back-end to kill")
            backend = model.getContainer(model.BACKEND_NAME)
            backend.terminate()
            return 0

        # check if there is already a backend running
        if status == BACKEND_RUNNING:
            raise IOError("Back-end already running, cannot start a new one")

        if options.model is None:
            raise ValueError("No microscope model instantiation file provided")

        if options.settings is None:
            try:
                options.settings = open(DEFAULT_SETTINGS_FILE, "a+")
            except IOError as ex:
                logging.warning("%s. Will not be able to use persistent data", ex)

        if options.debug:
            cont_pol = BackendRunner.CONTAINER_ALL_IN_ONE
        else:
            cont_pol = BackendRunner.CONTAINER_SEPARATED

        # let's become the back-end for real
        runner = BackendRunner(options.model, options.settings, options.daemon,
                               dry_run=options.validate, containement=cont_pol)
        runner.run()
    except ValueError as exp:
        logging.error("%s", exp)
        return 127
    except IOError as exp:
        logging.error("%s", exp)
        return 129
    except Exception:
        logging.exception("Unexpected error while performing action.")
        return 130

    return 0
Exemple #31
0
def main(args):
    """
    Contains the console handling code for the daemon
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    #print args
    # arguments handling
    parser = argparse.ArgumentParser(description=odemis.__fullname__)

    parser.add_argument('--version', dest="version", action='store_true',
                        help="show program's version number and exit")
    dm_grp = parser.add_argument_group('Daemon management')
    dm_grpe = dm_grp.add_mutually_exclusive_group()
    dm_grpe.add_argument("--kill", "-k", dest="kill", action="store_true", default=False,
                         help="Kill the running back-end")
    dm_grpe.add_argument("--check", dest="check", action="store_true", default=False,
                        help="Check for a running back-end (only returns exit code)")
    dm_grpe.add_argument("--daemonize", "-D", action="store_true", dest="daemon",
                         default=False, help="Daemonize the back-end after startup")
    opt_grp = parser.add_argument_group('Options')
    opt_grp.add_argument('--validate', dest="validate", action="store_true", default=False,
                         help="Validate the microscope description file and exit")
    dm_grpe.add_argument("--debug", action="store_true", dest="debug",
                         default=False, help="Activate debug mode, where everything runs in one process")
    opt_grp.add_argument("--log-level", dest="loglev", metavar="LEVEL", type=int,
                         default=0, help="Set verbosity level (0-2, default = 0)")
    opt_grp.add_argument("--log-target", dest="logtarget", metavar="{auto,stderr,filename}",
                         default="auto", help="Specify the log target (auto, stderr, filename)")
    parser.add_argument("model", metavar="file.odm.yaml", nargs='?', type=open,
                        help="Microscope model instantiation file (*.odm.yaml)")

    options = parser.parse_args(args[1:])

    # Cannot use the internal feature, because it doesn't support multiline
    if options.version:
        print (odemis.__fullname__ + " " + odemis.__version__ + "\n" +
               odemis.__copyright__ + "\n" +
               "Licensed under the " + odemis.__license__)
        return 0

    # Set up logging before everything else
    if options.loglev < 0:
        parser.error("log-level must be positive.")
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # auto = {odemis.log if daemon, stderr otherwise}
    if options.logtarget == "auto":
        # default to SysLogHandler ?
        if options.daemon:
            # Rotate the log, with max 500Mb used
            handler = RotatingFileHandler("odemis.log",
                                    maxBytes=100 * (2 ** 20), backupCount=5)
        else:
            handler = logging.StreamHandler()
    elif options.logtarget == "stderr":
        handler = logging.StreamHandler()
    else:
        handler = RotatingFileHandler(options.logtarget,
                                      maxBytes=100 * (2 ** 20), backupCount=5)
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(logging.Formatter('%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    # Useful to debug cases of multiple conflicting installations
    logging.debug("Starting Odemis back-end (from %s)", __file__)

    if options.validate and (options.kill or options.check or options.daemon):
        logging.error("Impossible to validate a model and manage the daemon simultaneously")
        return 127

    # Daemon management
    # python-daemon is a fancy library but seems to do too many things for us.
    # We just need to contact the backend and see what happens
    status = get_backend_status()
    if options.kill:
        if status != BACKEND_RUNNING:
            logging.error("No running back-end to kill")
            return 127
        try:
            backend = model.getContainer(model.BACKEND_NAME)
            backend.terminate()
        except:
            logging.error("Failed to stop the back-end")
            return 127
        return 0
    elif options.check:
        logging.info("Status of back-end is %s", status)
        return status_to_xtcode[status]

    # check if there is already a backend running
    if status == BACKEND_RUNNING:
        logging.error("Back-end already running, cannot start a new one")

    if options.model is None:
        logging.error("No microscope model instantiation file provided")
        return 127

    if options.debug:
        #cont_pol = BackendRunner.CONTAINER_DISABLE
        cont_pol = BackendRunner.CONTAINER_ALL_IN_ONE
    else:
        cont_pol = BackendRunner.CONTAINER_SEPARATED

    # let's become the back-end for real
    runner = BackendRunner(options.model, options.daemon, options.validate, cont_pol)
    return runner.run()
Exemple #32
0
def main(args):
    """ Parse the command line arguments and launch the Odemis daemon

    Args:
        args ([str]): The arguments passed to the executable

    Returns:
        int: Value to return to the OS as program exit code

    """

    # arguments handling
    parser = argparse.ArgumentParser(prog="odemis-start",
                                     description="Odemis starter program")

    parser.add_argument('model_conf',
                        nargs='?',
                        help="Model definition (yaml) file to use")
    parser.add_argument(
        '-s',
        '--selector',
        dest='model_sel',
        help="Model selector command (instead of using a model definition)")
    parser.add_argument(
        '-n',
        '--nogui',
        dest='nogui',
        action='store_true',
        help="Don't launch the GUI after the back end has started")
    parser.add_argument('-l',
                        '--log-target',
                        dest='logtarget',
                        help="Location of the back end log file")

    options = parser.parse_args(args[1:])

    if options.model_sel and options.model_conf:
        raise ValueError(
            "Cannot have both a model selector and model definition")

    # Use the log level for ourselves first
    try:
        loglevel = int(odemis_config["LOGLEVEL"])
        if options.logtarget:
            odemis_config['LOGFILE'] = options.logtarget
    except ValueError:
        loglevel = 1
        odemis_config["LOGLEVEL"] = "%d" % loglevel
    logging.getLogger().setLevel(loglevel)

    # pyrolog = logging.getLogger("Pyro4")
    # pyrolog.setLevel(min(pyrolog.getEffectiveLevel(), logging.DEBUG))

    try:
        # TODO: just bring the focus?
        # Kill GUI if an instance is already there
        # TODO: use psutil.process_iter() for this
        gui_killed = subprocess.call(
            ["/usr/bin/pkill", "-f", odemis_config["GUI"]])
        if gui_killed == 0:
            logging.info("Found the GUI still running, killing it first...")

        status = driver.get_backend_status()
        if status != driver.BACKEND_RUNNING:
            starter = BackendStarter(odemis_config, options.nogui)
            # TODO: if backend running but with a different model, also restart it
            if status == driver.BACKEND_DEAD:
                logging.warning(
                    "Back-end is not responding, will restart it...")
                # subprocess.call(["/usr/bin/pkill", "-f", config["BACKEND"]])
                subprocess.call(["sudo", "/usr/bin/odemis-stop"])
                time.sleep(3)

            try:
                if status in (driver.BACKEND_DEAD, driver.BACKEND_STOPPED):
                    starter.show_popup("Starting Odemis back-end")

                    # Get the model file in this order:
                    # 1. the command line (either model selector or model file)
                    # 2. the model file
                    # 3. the model selector
                    if options.model_conf:
                        modelfile = options.model_conf
                    elif options.model_sel:
                        modelfile = run_model_selector(options.model_sel)
                    elif "MODEL" in odemis_config:
                        modelfile = odemis_config["MODEL"]
                        if "MODEL_SELECTOR" in odemis_config:
                            logging.warning(
                                "Both MODEL and MODEL_SELECTOR defined in odemis.conf, using MODEL"
                            )
                    elif "MODEL_SELECTOR" in odemis_config:
                        modelfile = run_model_selector(
                            odemis_config["MODEL_SELECTOR"])
                    else:
                        raise ValueError("No microscope model specified")

                    starter.start_backend(modelfile)
                if status in (driver.BACKEND_DEAD, driver.BACKEND_STOPPED,
                              driver.BACKEND_STARTING):
                    starter.wait_backend_is_ready()
            except ValueError:
                raise  # Typically cancelled by user
            except IOError:
                starter.display_backend_log()
                raise
            except Exception as ex:
                # Something went very wrong (ie, back-end is blocked half-way
                # starting) => stop backend
                proc = subprocess.Popen(["sudo", "/usr/bin/odemis-stop"])
                show_error_box(
                    "Error starting Odemis back-end",
                    "Unexpected error while starting Odemis back-end:\n"
                    "%s\n\n"
                    "Try starting Odemis again, and use the \"Report a "
                    "problem\" function if the issue continues." % ex)
                proc.wait()
                raise
        else:
            logging.debug("Back-end already started, so not starting again")

        if not options.nogui:
            # Return when the GUI is done
            logging.info("Starting the GUI...")
            subprocess.check_call(
                ["odemis-gui", "--log-level", odemis_config["LOGLEVEL"]])

    except ValueError as exp:
        logging.error("%s", exp)
        return 127
    except IOError as exp:
        logging.error("%s", exp)
        return 129
    except Exception:
        logging.exception("Unexpected error while performing action.")
        return 130

    return 0
Exemple #33
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    # arguments handling
    parser = argparse.ArgumentParser(prog="odemis-cli",
                                     description=odemis.__fullname__)

    parser.add_argument('--version', dest="version", action='store_true',
                        help="show program's version number and exit")
    opt_grp = parser.add_argument_group('Options')
    opt_grp.add_argument("--log-level", dest="loglev", metavar="<level>", type=int,
                        default=0, help="set verbosity level (0-2, default = 0)")
    opt_grp.add_argument("--machine", dest="machine", action="store_true", default=False,
                         help="display in a machine-friendly way (i.e., no pretty printing)")
    dm_grp = parser.add_argument_group('Microscope management')
    dm_grpe = dm_grp.add_mutually_exclusive_group()
    dm_grpe.add_argument("--kill", "-k", dest="kill", action="store_true", default=False,
                         help="kill the running back-end")
    dm_grpe.add_argument("--check", dest="check", action="store_true", default=False,
                         help="check for a running back-end (only returns exit code)")
    dm_grpe.add_argument("--scan", dest="scan", action="store_true", default=False,
                         help="scan for possible devices to connect (the back-end must be stopped)")
    dm_grpe.add_argument("--list", "-l", dest="list", action="store_true", default=False,
                         help="list the components of the microscope")
    dm_grpe.add_argument("--list-prop", "-L", dest="listprop", metavar="<component>",
                         help="list the properties of a component")
    dm_grpe.add_argument("--set-attr", "-s", dest="setattr", nargs=3, action='append',
                         metavar=("<component>", "<attribute>", "<value>"),
                         help="set the attribute of a component (lists are delimited by commas,"
                         " dictionary keys are delimited by colon)")
    dm_grpe.add_argument("--move", "-m", dest="move", nargs=3, action='append',
                         metavar=("<component>", "<axis>", "<distance>"),
                         help=u"move the axis by the amount of µm.")
    dm_grpe.add_argument("--position", "-p", dest="position", nargs=3, action='append',
                         metavar=("<component>", "<axis>", "<position>"),
                         help=u"move the axis to the given position in µm.")
    dm_grpe.add_argument("--stop", "-S", dest="stop", action="store_true", default=False,
                         help="immediately stop all the actuators in all directions.")
    dm_grpe.add_argument("--acquire", "-a", dest="acquire", nargs="+",
                         metavar=("<component>", "data-flow"),
                         help="acquire an image (default data-flow is \"data\")")
    dm_grp.add_argument("--output", "-o", dest="output",
                        help="name of the file where the image should be saved after acquisition. The file format is derived from the extension (TIFF and HDF5 are supported).")
    dm_grpe.add_argument("--live", dest="live", nargs="+",
                         metavar=("<component>", "data-flow"),
                         help="display and update an image on the screen (default data-flow is \"data\")")

    options = parser.parse_args(args[1:])

    # To allow printing unicode even with pipes
    ensure_output_encoding()

    # Cannot use the internal feature, because it doesn't support multiline
    if options.version:
        print (odemis.__fullname__ + " " + odemis.__version__ + "\n" +
               odemis.__copyright__ + "\n" +
               "Licensed under the " + odemis.__license__)
        return 0

    # Set up logging before everything else
    if options.loglev < 0:
        parser.error("log-level must be positive.")
    # TODO: allow to put logging level so low that nothing is ever output
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # change the log format to be more descriptive
    handler = logging.StreamHandler()
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(logging.Formatter('%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    # anything to do?
    if (not options.check and not options.kill and not options.scan
        and not options.list and not options.stop and options.move is None
        and options.position is None
        and options.listprop is None and options.setattr is None
        and options.acquire is None and options.live is None):
        logging.error("no action specified.")
        return 127
    if options.acquire is not None and options.output is None:
        logging.error("name of the output file must be specified.")
        return 127


    logging.debug("Trying to find the backend")
    status = get_backend_status()
    if options.check:
        logging.info("Status of back-end is %s", status)
        return status_to_xtcode[status]

    # scan needs to have the backend stopped
    if options.scan:
        if status == BACKEND_RUNNING:
            logging.error("Back-end running while trying to scan for devices")
            return 127
        try:
            return scan()
        except Exception:
            logging.exception("Unexpected error while performing scan.")
            return 127

    # check if there is already a backend running
    if status == BACKEND_STOPPED:
        logging.error("No running back-end")
        return 127
    elif status == BACKEND_DEAD:
        logging.error("Back-end appears to be non-responsive.")
        return 127

    try:
        if options.kill:
            return kill_backend()

        logging.debug("Executing the actions")

        if options.list:
            return list_components(pretty=not options.machine)
        elif options.listprop is not None:
            # Speed up is only worthy if many VAs are accessed
            odemis.util.driver.speedUpPyroConnect(model.getMicroscope())
            return list_properties(options.listprop, pretty=not options.machine)
        elif options.setattr is not None:
            for c, a, v in options.setattr:
                ret = set_attr(c, a, v)
                if ret != 0:
                    return ret
        elif options.position is not None:
            for c, a, d in options.position:
                ret = move_abs(c, a, d)
                # TODO warn if same axis multiple times
                if ret != 0:
                    return ret
            time.sleep(0.5)
        elif options.move is not None:
            for c, a, d in options.move:
                ret = move(c, a, d)
                # TODO move commands to the same actuator should be agglomerated
                if ret != 0:
                    return ret
            time.sleep(0.5) # wait a bit for the futures to close nicely
        elif options.stop:
            return stop_move()
        elif options.acquire is not None:
            component = options.acquire[0]
            if len(options.acquire) == 1:
                dataflows = ["data"]
            else:
                dataflows = options.acquire[1:]
            filename = options.output.decode(sys.getfilesystemencoding())
            return acquire(component, dataflows, filename)
        elif options.live is not None:
            component = options.live[0]
            if len(options.live) == 1:
                dataflow = "data"
            elif len(options.live) == 2:
                dataflow = options.acquire[2]
            else:
                logging.error("live command accepts only one data-flow")
                return 127
            return live_display(component, dataflow)
    except:
        logging.exception("Unexpected error while performing action.")
        return 127

    return 0
Exemple #34
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """
    # arguments handling
    parser = argparse.ArgumentParser()
    group = parser.add_mutually_exclusive_group()
    group.add_argument("--role",
                       dest="role",
                       metavar="<component>",
                       help="display and update an image on the screen")
    group.add_argument("--file",
                       metavar="<filename>",
                       dest="filename",
                       help="display and update an image on the screen")
    parser.add_argument("--gridsize",
                        dest="gridsize",
                        nargs=2,
                        metavar="<gridsize>",
                        type=int,
                        default=None,
                        help="size of the grid of spots in x y, default 8 8")
    parser.add_argument("--magnification",
                        dest="magnification",
                        type=float,
                        help="magnification (typically 40 or 50)")
    parser.add_argument("--log-level",
                        dest="loglev",
                        metavar="<level>",
                        type=int,
                        choices=[0, 1, 2],
                        default=0,
                        help="set verbosity level (0-2, default = 0)")
    options = parser.parse_args(args[1:])
    # Set up logging before everything else
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # change the log format to be more descriptive
    handler = logging.StreamHandler()
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(
        logging.Formatter(
            '%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    # Magnification: use cli input value. If none is specified, try to read out lens magnification.
    try:
        lens = model.getComponent(role="lens")
        lens_mag = lens.magnification.value
    except Exception as ex:
        logging.debug("Failed to read magnification from lens, ex: %s", ex)
        lens_mag = None

    if options.magnification:
        magnification = options.magnification
        if lens_mag and lens_mag != magnification:
            logging.warning(
                "Requested magnification %s differs from lens magnification %s.",
                magnification, lens_mag)
    elif lens_mag:
        magnification = lens_mag
        logging.debug(
            "No magnification specified, using lens magnification %s.",
            lens_mag)
    else:
        magnification = DEFAULT_MAGNIFICATION
        logging.warning("No magnification specified, falling back to %s.",
                        magnification)
    pxsize = PIXEL_SIZE_SAMPLE_PLANE / magnification

    if options.filename:
        logging.info("Will process image file %s" % options.filename)
        converter = dataio.find_fittest_converter(options.filename,
                                                  default=None,
                                                  mode=os.O_RDONLY)
        data = converter.read_data(options.filename)[0]
        fakeccd = StaticCCD(options.filename, "fakeccd", data)
        live_display(fakeccd, fakeccd.data, pxsize, gridsize=options.gridsize)
    elif options.role:
        if get_backend_status() != BACKEND_RUNNING:
            raise ValueError(
                "Backend is not running while role command is specified.")
        ccd = model.getComponent(role=options.role)
        live_display(ccd,
                     ccd.data,
                     pxsize,
                     kill_ccd=False,
                     gridsize=options.gridsize)
    else:
        ccd = ueye.Camera("camera", "ccd", device=None)
        ccd.SetFrameRate(2)
        live_display(ccd, ccd.data, pxsize, gridsize=options.gridsize)
    return 0
Exemple #35
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    # arguments handling
    parser = argparse.ArgumentParser(prog="odemis-cli",
                                     description=odemis.__fullname__)

    parser.add_argument('--version', dest="version", action='store_true',
                        help="show program's version number and exit")
    opt_grp = parser.add_argument_group('Options')
    opt_grp.add_argument("--log-level", dest="loglev", metavar="<level>", type=int,
                         default=0, help="set verbosity level (0-2, default = 0)")
    opt_grp.add_argument("--machine", dest="machine", action="store_true", default=False,
                         help="display in a machine-friendly way (i.e., no pretty printing)")
    dm_grp = parser.add_argument_group('Microscope management')
    dm_grpe = dm_grp.add_mutually_exclusive_group()
    dm_grpe.add_argument("--kill", "-k", dest="kill", action="store_true", default=False,
                         help="kill the running back-end")
    dm_grpe.add_argument("--check", dest="check", action="store_true", default=False,
                         help="check for a running back-end (only returns exit code)")
    dm_grpe.add_argument("--scan", dest="scan", const=True, default=False, nargs="?",
                         metavar="class",
                         help="scan for possible devices to connect (the "
                         "back-end must be stopped). Optionally class name of "
                         "a specific hardware to scan can be specified.")
    dm_grpe.add_argument("--list", "-l", dest="list", action="store_true", default=False,
                         help="list the components of the microscope")
    dm_grpe.add_argument("--list-prop", "-L", dest="listprop", metavar="<component>",
                         help="list the properties of a component. Use '*' to list all the components.")
    dm_grpe.add_argument("--set-attr", "-s", dest="setattr", nargs="+", action='append',
                         metavar=("<component>", "<attribute>"),
                         help="set the attribute of a component. First the component name, "
                         "then a series of attribute/value to be set. "
                         "(Lists are delimited by commas, dictionary keys are delimited by colon)")
    dm_grpe.add_argument("--update-metadata", "-u", dest="upmd", nargs="+", action='append',
                         metavar=("<component>", "<key>"),
                         help="update the metadata entry of a component. First the component name, "
                         "then a series of key/value to be set. "
                         "(Lists are delimited by commas)")
    dm_grpe.add_argument("--move", "-m", dest="move", nargs=3, action='append',
                         metavar=("<component>", "<axis>", "<distance>"),
                         help=u"move the axis by the given amount (µm for distances).")
    dm_grpe.add_argument("--position", "-p", dest="position", nargs=3, action='append',
                         metavar=("<component>", "<axis>", "<position>"),
                         help=u"move the axis to the given position.")
    dm_grp.add_argument("--big-distance", dest="bigdist", action="store_true", default=False,
                        help=u"flag needed to allow any move bigger than 10 mm.")
    dm_grpe.add_argument("--reference", dest="reference", nargs=2, action="append",
                         metavar=("<component>", "<axis>"),
                         help="runs the referencing procedure for the given axis.")
    dm_grpe.add_argument("--stop", "-S", dest="stop", action="store_true", default=False,
                         help="immediately stop all the actuators in all directions.")
    dm_grpe.add_argument("--acquire", "-a", dest="acquire", nargs="+",
                         metavar=("<component>", "data-flow"),
                         help="acquire an image (default data-flow is \"data\")")
    dm_grp.add_argument("--output", "-o", dest="output",
                        help="name of the file where the image should be saved "
                        "after acquisition. The file format is derived from the extension "
                        "(TIFF and HDF5 are supported).")
    dm_grpe.add_argument("--live", dest="live", nargs="+",
                         metavar=("<component>", "data-flow"),
                         help="display and update an image on the screen (default data-flow is \"data\")")

    options = parser.parse_args(args[1:])

    # To allow printing unicode even with pipes
    ensure_output_encoding()

    # Cannot use the internal feature, because it doesn't support multiline
    if options.version:
        print (odemis.__fullname__ + " " + odemis.__version__ + "\n" +
               odemis.__copyright__ + "\n" +
               "Licensed under the " + odemis.__license__)
        return 0

    # Set up logging before everything else
    if options.loglev < 0:
        logging.error("Log-level must be positive.")
        return 127
    # TODO: allow to put logging level so low that nothing is ever output
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # change the log format to be more descriptive
    handler = logging.StreamHandler()
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(logging.Formatter('%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    if loglev <= logging.DEBUG:
        # Activate also Pyro logging
        # TODO: options.logtarget
        pyrolog = logging.getLogger("Pyro4")
        pyrolog.setLevel(min(pyrolog.getEffectiveLevel(), logging.INFO))

    # anything to do?
    if not any((options.check, options.kill, options.scan,
        options.list, options.stop, options.move,
        options.position, options.reference,
        options.listprop, options.setattr, options.upmd,
        options.acquire, options.live)):
        logging.error("No action specified.")
        return 127
    if options.acquire is not None and options.output is None:
        logging.error("Name of the output file must be specified.")
        return 127
    if options.setattr:
        for l in options.setattr:
            if len(l) < 3 or (len(l) - 1) % 2 == 1:
                logging.error("--set-attr expects component name and then a even number of arguments")
    if options.upmd:
        for l in options.upmd:
            if len(l) < 3 or (len(l) - 1) % 2 == 1:
                logging.error("--update-metadata expects component name and then a even number of arguments")

    logging.debug("Trying to find the backend")
    status = get_backend_status()
    if options.check:
        logging.info("Status of back-end is %s", status)
        return status_to_xtcode[status]

    try:
        # scan needs to have the backend stopped
        if options.scan:
            if status == BACKEND_RUNNING:
                raise ValueError("Back-end running while trying to scan for devices")
            if isinstance(options.scan, basestring):
                scan(options.scan)
            else:
                scan()
            return 0

        # check if there is already a backend running
        if status == BACKEND_STOPPED:
            raise IOError("No running back-end")
        elif status == BACKEND_DEAD:
            raise IOError("Back-end appears to be non-responsive.")

        logging.debug("Executing the actions")

        if options.kill:
            kill_backend()
        elif options.list:
            list_components(pretty=not options.machine)
        elif options.listprop is not None:
            list_properties(options.listprop, pretty=not options.machine)
        elif options.setattr is not None:
            for l in options.setattr:
                # C A B E F => C, {A: B, E: F}
                c = l[0]
                avs = dict(zip(l[1::2], l[2::2]))
                set_attr(c, avs)
        elif options.upmd is not None:
            for l in options.upmd:
                c = l[0]
                kvs = dict(zip(l[1::2], l[2::2]))
                update_metadata(c, kvs)
        # TODO: catch keyboard interrupt and stop the moves
        elif options.reference is not None:
            for c, a in options.reference:
                reference(c, a)
        elif options.position is not None:
            moves = merge_moves(options.position)
            for c, m in moves.items():
                move_abs(c, m, check_distance=(not options.bigdist))
        elif options.move is not None:
            moves = merge_moves(options.move)
            for c, m in moves.items():
                move(c, m, check_distance=(not options.bigdist))
        elif options.stop:
            stop_move()
        elif options.acquire is not None:
            component = options.acquire[0]
            if len(options.acquire) == 1:
                dataflows = ["data"]
            else:
                dataflows = options.acquire[1:]
            filename = options.output.decode(sys.getfilesystemencoding())
            acquire(component, dataflows, filename)
        elif options.live is not None:
            component = options.live[0]
            if len(options.live) == 1:
                dataflow = "data"
            elif len(options.live) == 2:
                dataflow = options.acquire[2]
            else:
                raise ValueError("Live command accepts only one data-flow")
            live_display(component, dataflow)
    except KeyboardInterrupt:
        logging.info("Interrupted before the end of the execution")
        return 1
    except ValueError as exp:
        logging.error("%s", exp)
        return 127
    except IOError as exp:
        logging.error("%s", exp)
        return 129
    except Exception:
        logging.exception("Unexpected error while performing action.")
        return 130

    return 0
Exemple #36
0
def main(args):
    """
    Handles the command line arguments
    args is the list of arguments passed
    return (int): value to return to the OS as program exit code
    """

    # arguments handling
    parser = argparse.ArgumentParser(prog="odemis-cli",
                                     description=odemis.__fullname__)

    parser.add_argument('--version', dest="version", action='store_true',
                        help="show program's version number and exit")
    opt_grp = parser.add_argument_group('Options')
    opt_grp.add_argument("--log-level", dest="loglev", metavar="<level>", type=int,
                         default=0, help="set verbosity level (0-2, default = 0)")
    opt_grp.add_argument("--machine", dest="machine", action="store_true", default=False,
                         help="display in a machine-friendly way (i.e., no pretty printing)")
    dm_grp = parser.add_argument_group('Microscope management')
    dm_grpe = dm_grp.add_mutually_exclusive_group()
    dm_grpe.add_argument("--kill", "-k", dest="kill", action="store_true", default=False,
                         help="kill the running back-end")
    dm_grpe.add_argument("--check", dest="check", action="store_true", default=False,
                         help="check for a running back-end (only returns exit code)")
    dm_grpe.add_argument("--scan", dest="scan", const=True, default=False, nargs="?",
                         metavar="class",
                         help="scan for possible devices to connect (the "
                         "back-end must be stopped). Optionally class name of "
                         "a specific hardware to scan can be specified.")
    dm_grpe.add_argument("--list", "-l", dest="list", action="store_true", default=False,
                         help="list the components of the microscope")
    dm_grpe.add_argument("--list-prop", "-L", dest="listprop", metavar="<component>",
                         help="list the properties of a component. Use '*' to list all the components.")
    dm_grpe.add_argument("--set-attr", "-s", dest="setattr", nargs="+", action='append',
                         metavar=("<component>", "<attribute>"),
                         help="set the attribute of a component. First the component name, "
                         "then a series of attribute/value to be set. "
                         "(Lists are delimited by commas, dictionary keys are delimited by colon)")
    dm_grpe.add_argument("--update-metadata", "-u", dest="upmd", nargs="+", action='append',
                         metavar=("<component>", "<key>"),
                         help="update the metadata entry of a component. First the component name, "
                         "then a series of key/value to be set. "
                         "(Lists are delimited by commas)")
    dm_grpe.add_argument("--move", "-m", dest="move", nargs=3, action='append',
                         metavar=("<component>", "<axis>", "<distance>"),
                         help=u"move the axis by the given amount (µm for distances).")
    dm_grpe.add_argument("--position", "-p", dest="position", nargs=3, action='append',
                         metavar=("<component>", "<axis>", "<position>"),
                         help=u"move the axis to the given position.")
    dm_grp.add_argument("--big-distance", dest="bigdist", action="store_true", default=False,
                        help=u"flag needed to allow any move bigger than 10 mm.")
    dm_grpe.add_argument("--reference", dest="reference", nargs=2, action="append",
                         metavar=("<component>", "<axis>"),
                         help="runs the referencing procedure for the given axis.")
    dm_grpe.add_argument("--stop", "-S", dest="stop", action="store_true", default=False,
                         help="immediately stop all the actuators in all directions.")
    dm_grpe.add_argument("--acquire", "-a", dest="acquire", nargs="+",
                         metavar=("<component>", "data-flow"),
                         help="acquire an image (default data-flow is \"data\")")
    dm_grp.add_argument("--output", "-o", dest="output",
                        help="name of the file where the image should be saved "
                        "after acquisition. The file format is derived from the extension "
                        "(TIFF and HDF5 are supported).")
    dm_grpe.add_argument("--live", dest="live", nargs="+",
                         metavar=("<component>", "data-flow"),
                         help="display and update an image on the screen (default data-flow is \"data\")")

    # To allow printing unicode even with pipes
    ensure_output_encoding()

    options = parser.parse_args(args[1:])

    # Cannot use the internal feature, because it doesn't support multiline
    if options.version:
        print(odemis.__fullname__ + " " + odemis.__version__ + "\n" +
              odemis.__copyright__ + "\n" +
              "Licensed under the " + odemis.__license__)
        return 0

    # Set up logging before everything else
    if options.loglev < 0:
        logging.error("Log-level must be positive.")
        return 127
    # TODO: allow to put logging level so low that nothing is ever output
    loglev_names = [logging.WARNING, logging.INFO, logging.DEBUG]
    loglev = loglev_names[min(len(loglev_names) - 1, options.loglev)]

    # change the log format to be more descriptive
    handler = logging.StreamHandler()
    logging.getLogger().setLevel(loglev)
    handler.setFormatter(logging.Formatter('%(asctime)s (%(module)s) %(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)

    if loglev <= logging.DEBUG:
        # Activate also Pyro logging
        # TODO: options.logtarget
        pyrolog = logging.getLogger("Pyro4")
        pyrolog.setLevel(min(pyrolog.getEffectiveLevel(), logging.INFO))

    # anything to do?
    if not any((options.check, options.kill, options.scan,
        options.list, options.stop, options.move,
        options.position, options.reference,
        options.listprop, options.setattr, options.upmd,
        options.acquire, options.live)):
        logging.error("No action specified.")
        return 127
    if options.acquire is not None and options.output is None:
        logging.error("Name of the output file must be specified.")
        return 127
    if options.setattr:
        for l in options.setattr:
            if len(l) < 3 or (len(l) - 1) % 2 == 1:
                logging.error("--set-attr expects component name and then a even number of arguments")
                return 127
    if options.upmd:
        for l in options.upmd:
            if len(l) < 3 or (len(l) - 1) % 2 == 1:
                logging.error("--update-metadata expects component name and then a even number of arguments")
                return 127

    logging.debug("Trying to find the backend")
    status = get_backend_status()
    if options.check:
        logging.info("Status of back-end is %s", status)
        return status_to_xtcode[status]

    try:
        # scan needs to have the backend stopped
        if options.scan:
            if status == BACKEND_RUNNING:
                raise ValueError("Back-end running while trying to scan for devices")
            if isinstance(options.scan, basestring):
                scan(options.scan)
            else:
                scan()
            return 0

        # check if there is already a backend running
        if status == BACKEND_STOPPED:
            raise IOError("No running back-end")
        elif status == BACKEND_DEAD:
            raise IOError("Back-end appears to be non-responsive.")

        logging.debug("Executing the actions")

        if options.kill:
            kill_backend()
        elif options.list:
            list_components(pretty=not options.machine)
        elif options.listprop is not None:
            list_properties(options.listprop, pretty=not options.machine)
        elif options.setattr is not None:
            for l in options.setattr:
                # C A B E F => C, {A: B, E: F}
                c = l[0]
                avs = dict(zip(l[1::2], l[2::2]))
                set_attr(c, avs)
        elif options.upmd is not None:
            for l in options.upmd:
                c = l[0]
                kvs = dict(zip(l[1::2], l[2::2]))
                update_metadata(c, kvs)
        # TODO: catch keyboard interrupt and stop the moves
        elif options.reference is not None:
            for c, a in options.reference:
                reference(c, a)
        elif options.position is not None:
            moves = merge_moves(options.position)
            for c, m in moves.items():
                move_abs(c, m, check_distance=(not options.bigdist))
        elif options.move is not None:
            moves = merge_moves(options.move)
            for c, m in moves.items():
                move(c, m, check_distance=(not options.bigdist))
        elif options.stop:
            stop_move()
        elif options.acquire is not None:
            component = options.acquire[0]
            if len(options.acquire) == 1:
                dataflows = ["data"]
            else:
                dataflows = options.acquire[1:]
            if isinstance(options.output, unicode):  # python3
                filename = options.output
            else:  # python2
                filename = options.output.decode(sys.getfilesystemencoding())
            acquire(component, dataflows, filename)
        elif options.live is not None:
            component = options.live[0]
            if len(options.live) == 1:
                dataflow = "data"
            elif len(options.live) == 2:
                dataflow = options.acquire[2]
            else:
                raise ValueError("Live command accepts only one data-flow")
            live_display(component, dataflow)
    except KeyboardInterrupt:
        logging.info("Interrupted before the end of the execution")
        return 1
    except ValueError as exp:
        logging.error("%s", exp)
        return 127
    except IOError as exp:
        logging.error("%s", exp)
        return 129
    except Exception:
        logging.exception("Unexpected error while performing action.")
        return 130

    return 0
Exemple #37
0
 def tearDownClass(cls):
     # turn off everything when the testing finished.
     if driver.get_backend_status() == driver.BACKEND_RUNNING:
         test.stop_backend()