Exemple #1
0
    def get_elements_with_interface(self, interface):
        ret = CaselessDict()
        if is_pure_str(interface):
            interface_str = interface
            interface = Interface[interface_str]
        else:
            interface_str = Interface[interface]

        if self.is_macroserver_interface(interface):
            ret.update(self._LOCAL_INTERFACES.get(interface)(self))
        else:
            for pool in self.get_pools():
                ret.update(pool.getElementsWithInterface(interface_str))
        return ret
Exemple #2
0
 def __init__(self, name, image_name='image', image_ct='imagecounter', **kw):
     self._image_data = CaselessDict()
     self._image_id_attr_name = image_ct
     self.call__init__(ImageDevice, name, image_name, **kw)
     self._busy = False
     self._image_id_attr = self.getAttribute(self._image_id_attr_name)
     self._image_id_attr.addListener(self)
Exemple #3
0
    def __init__(self):
        # dict<str, dict> where key is the type and value is:
        #     dict<str, MacroServerElement> where key is the element full name
        #                                   and value is the Element object
        self._type_elems_dict = CaselessDict()

        # dict<str, container> where key is the interface and value is the set
        # of elements which implement that interface
        self._interfaces_dict = {}
Exemple #4
0
    def __init__(self, initial_elems):
        MoveableSource.__init__(self)
        self.elem_names = initial_elems
        self.moveable_inc = 0

        self.motors = CaselessDict()
        for elem_name in initial_elems:
            self.motors[elem_name] = PoolMoveableTest(elem_name, [elem_name], self)
        self.motor_group = None
    def __init__(self):
        #: dict<int(axis), str(reason for being in pending)>
        self._pending = {}

        #: dict<str(dev name), tuple<DeviceProxy, list<str(attributes name)>>>
        self._devices = CaselessDict()

        #: dict<int(axis), seq<str<tango full attribute name>, str<attr name>, DeviceProxy>>
        self._axis_tango_attributes = {}

        #: dict<int(axis), str<formula>>
        self._axis_formulas = {}
    def __init__(self):

        # map of all elements
        # key - element ID
        # value - pointer to the element object
        self._element_ids = {}

        # map of all elements by name
        # key - element name
        # value - pointer to the element object
        self._element_names = CaselessDict()

        # map of all elements by name
        # key - element full name
        # value - pointer to the element object
        self._element_full_names = CaselessDict()

        # map of all elements by type
        # key - element type
        # value - map where:
        #    key - element ID
        #    value - pointer to the element object
        self._element_types = {}
Exemple #7
0
    def __init__(self, name, **kw):
        self._log_attr = CaselessDict()
        self._block_lines = 0
        self._in_block = False
        self._macro_server = None
        self._running_macros = None
        self._running_macro = None
        self._last_running_macro = None
        self._user_xml = None
        self._ignore_logs = kw.get("ignore_logs", False)
        self._silent = kw.get("silent", True)
        self._debug = kw.get("debug", False)
        self._output_stream = kw.get("output", sys.stdout)
        self._writeLock = threading.Lock()
        self._input_handler = self.create_input_handler()

        self.call__init__(MacroServerDevice, name, **kw)

        self._old_door_state = PyTango.DevState.UNKNOWN
        try:
            self._old_sw_door_state = TaurusSWDevState.Uninitialized
        except RuntimeError:
            #TODO: For Taurus 4 compatibility
            from taurus.core import TaurusDevState
            self._old_sw_door_state = TaurusDevState.Undefined 

        self.getStateObj().addListener(self.stateChanged)

        for log_name in self.log_streams:
            tg_attr = self.getAttribute(log_name)
            attr = LogAttr(self, log_name, None, tg_attr)
            if log_name == 'Result':
                attr.subscribeEvent(self.resultReceived, log_name)
            else:
                attr.subscribeEvent(self.logReceived, log_name)
            self._log_attr[log_name] = attr

        input_attr = self.getAttribute("Input")
        input_attr.addListener(self.inputReceived)

        record_data_attr = self.getAttribute('RecordData')
        record_data_attr.addListener(self.recordDataReceived)

        macro_status_attr = self.getAttribute('MacroStatus')
        macro_status_attr.addListener(self.macroStatusReceived)

        self._experiment_configuration = ExperimentConfiguration(self)
Exemple #8
0
    def reInit(self):
        """Reinitialize the singleton"""
        self._default_tango_host = None
        self.dft_db = None
        self.tango_db = CaselessWeakValueDict()
        self.tango_db_queries = CaselessWeakValueDict()
        self.tango_attrs = CaselessWeakValueDict()
        self.tango_devs = CaselessWeakValueDict()
        self.tango_dev_queries = CaselessWeakValueDict()
        self.tango_alias_devs = CaselessWeakValueDict()
        self.polling_timers = {}

        # Plugin device classes
        self.tango_dev_klasses = {}

        # Plugin attribute classes
        self.tango_attr_klasses = CaselessDict()
Exemple #9
0
class PoolMSTest(MoveableSource):
    def __init__(self, initial_elems):
        MoveableSource.__init__(self)
        self.elem_names = initial_elems
        self.moveable_inc = 0

        self.motors = CaselessDict()
        for elem_name in initial_elems:
            self.motors[elem_name] = PoolMoveableTest(elem_name, [elem_name], self)
        self.motor_group = None

    def getMoveable(self, names):
        if len(names) == 1:
            return self.motors.get(names[0])
        l = [name for name in self.elem_names if name in names]
        self.motor_group = PoolMoveableTest("moveable %d" % self.moveable_inc, l, self)
        self.moveable_inc += 1
        return self.motor_group
Exemple #10
0
    def __init__(self, full_name, name=None, macro_path=None, environment_db=None, recorder_path=None):
        # dict<str, Pool>
        # key   - device name (case insensitive)
        # value - Pool object representing the device name
        self._pools = CaselessDict()
        self._max_parallel_macros = self.MaxParalellMacros
        self._path_id = None

        MSContainer.__init__(self)
        MSObject.__init__(
            self, full_name=full_name, name=name, id=InvalidId, macro_server=self, elem_type=ElementType.MacroServer
        )

        registerExtensions()

        self._type_manager = TypeManager(self)
        self._environment_manager = EnvironmentManager(self, environment_db=environment_db)
        self._macro_manager = MacroManager(self, macro_path=macro_path)
        self._recorder_manager = RecorderManager(self, recorder_path=recorder_path)
 def toDataInfo(klass, name, info):
     info = CaselessDict(info)
     dtype = info[Type]
     dtype, dformat = to_dtype_dformat(dtype)
     default_value = info.get(DefaultValue)
     description = info.get(Description, '')
     daccess = info.get(Access, DataAccess.ReadWrite)
     daccess = to_daccess(daccess)
     memorized = info.get(Memorize, Memorized)
     maxdimsize = info.get(MaxDimSize)
     fget = info.get(FGet)
     fset = info.get(FSet)
     if default_value is not None and dtype != DataType.String:
         if type(default_value) in types.StringTypes:
             default_value = eval(default_value)
     return DataInfo(name, dtype, dformat=dformat, access=daccess,
                     description=description, default_value=default_value,
                     memorized=memorized, fget=fget, fset=fset,
                     maxdimsize=maxdimsize)
Exemple #12
0
    def __init__(self, full_name, name=None):
        self._path_id = None
        self._motion_loop_states_per_position = self.Default_MotionLoop_StatesPerPosition
        self._motion_loop_sleep_time = self.Default_MotionLoop_SleepTime
        self._acq_loop_states_per_value = self.Default_AcqLoop_StatesPerValue
        self._acq_loop_sleep_time = self.Default_AcqLoop_SleepTime
        self._drift_correction = self.Default_DriftCorrection
        self._remote_log_handler = None

        # dict<str, dict<str, str>>
        # keys are acquisition channel names and value is a dict describing the
        # channel containing:
        #  - 'name': with value being the channel name (given by user)
        #  - 'full_name': acq channel full name (ex: tango attribute)
        #  - 'origin': 'local' if local to this server or 'remote' if a remote
        #    channel
        self._extra_acquisition_element_names = CaselessDict()

        PoolContainer.__init__(self)
        PoolObject.__init__(self, full_name=full_name, name=name, id=InvalidId,
                            pool=self, elem_type=ElementType.Pool)
        self._monitor = PoolMonitor(self, "PMonitor", auto_start=False)
        # self.init_local_logging()
        ControllerManager().set_pool(self)
Exemple #13
0
class _PoolUtil(object):

    def __init__(self):
        self._ctrl_proxies = CaselessDict()

    def __call__(self, *args, **kwargs):
        return self

    def get_device(self, *args, **kwargs):
        ctrl_name = args[0]
        device_name = args[1]
        ctrl_devs = self._ctrl_proxies.get(ctrl_name)
        if ctrl_devs is None:
            self._ctrl_proxies[ctrl_name] = ctrl_devs = CaselessDict()
        dev = ctrl_devs.get(device_name)
        if dev is None:
            import PyTango
            ctrl_devs[device_name] = dev = PyTango.DeviceProxy(device_name)
        return dev

    get_motor = get_phy_motor = get_pseudo_motor = get_motor_group = \
        get_exp_channel = get_ct_channel = get_zerod_channel = get_oned_channel = \
        get_twod_channel = get_pseudo_counter_channel = get_measurement_group = \
        get_com_channel = get_ioregister = get_device
Exemple #14
0
 def __init__(self):
     self._ctrl_proxies = CaselessDict()
Exemple #15
0
 def __init__(self):
     self._ctrl_proxies = CaselessDict()
     self._lock = threading.Lock()
Exemple #16
0
 def __init__(self):
     self._ctrl_proxies = CaselessDict()
Exemple #17
0
class Pool(PoolContainer, PoolObject, SardanaElementManager, SardanaIDManager):
    """The central pool class."""

    #: Default value representing the number of state reads per position
    #: read during a motion loop
    Default_MotionLoop_StatesPerPosition = 10

    #: Default value representing the sleep time for each motion loop
    Default_MotionLoop_SleepTime = 0.01

    #: Default value representing the number of state reads per value
    #: read during a motion loop
    Default_AcqLoop_StatesPerValue = 10

    #: Default value representing the sleep time for each acquisition loop
    Default_AcqLoop_SleepTime = 0.01

    Default_DriftCorrection = True

    def __init__(self, full_name, name=None):
        self._path_id = None
        self._motion_loop_states_per_position = self.Default_MotionLoop_StatesPerPosition
        self._motion_loop_sleep_time = self.Default_MotionLoop_SleepTime
        self._acq_loop_states_per_value = self.Default_AcqLoop_StatesPerValue
        self._acq_loop_sleep_time = self.Default_AcqLoop_SleepTime
        self._drift_correction = self.Default_DriftCorrection
        self._remote_log_handler = None

        # dict<str, dict<str, str>>
        # keys are acquisition channel names and value is a dict describing the
        # channel containing:
        #  - 'name': with value being the channel name (given by user)
        #  - 'full_name': acq channel full name (ex: tango attribute)
        #  - 'origin': 'local' if local to this server or 'remote' if a remote
        #    channel
        self._extra_acquisition_element_names = CaselessDict()

        PoolContainer.__init__(self)
        PoolObject.__init__(self, full_name=full_name, name=name, id=InvalidId,
                            pool=self, elem_type=ElementType.Pool)
        self._monitor = PoolMonitor(self, "PMonitor", auto_start=False)
        # self.init_local_logging()
        ControllerManager().set_pool(self)

    # TODO: not ready to use. path must be the same as the one calculated in
    # sardana.tango.core.util:prepare_logging
    def init_local_logging(self):
        log = logging.getLogger("Controller")
        log.propagate = 0
        path = os.path.join(os.sep, "tmp", "tango")
        log_file_name = os.path.join(path, 'controller.log.txt')
        try:
            if not os.path.exists(path):
                os.makedirs(path, 0777)
            f_h = logging.handlers.RotatingFileHandler(log_file_name,
                                                       maxBytes=1E7,
                                                       backupCount=5)

            f_h.setFormatter(self.getLogFormat())
            log.addHandler(f_h)
            self.info("Controller logs stored in %s", log_file_name)
        except:
            self.warning("Controller logs could not be created!")
            self.debug("Details:", exc_info=1)

    def clear_remote_logging(self):
        rh = self._remote_log_handler
        if rh is None:
            return
        log = logging.getLogger("Controller")
        log.removeHandler(rh)
        self._remote_log_handler = None

    def init_remote_logging(self, host=None, port=None):
        """Initializes remote logging.

        :param host: host name [default: None, meaning use the machine host name
                     as returned by :func:`socket.gethostname`].
        :type host: :obj:`str`
        :param port: port number [default: None, meaning use
                     :data:`logging.handlers.DEFAULT_TCP_LOGGING_PORT`"""
        log = logging.getLogger("Controller")

        # port 0 means no remote logging
        if port == 0:
            return

        # first check that the handler has not been initialized yet
        for handler in log.handlers:
            if isinstance(handler, logging.handlers.SocketHandler):
                return
        if host is None:
            import socket
            host = socket.gethostname()
            #host = socket.getfqdn()
        if port is None:
            port = logging.handlers.DEFAULT_TCP_LOGGING_PORT
        handler = logging.handlers.SocketHandler(host, port)
        if hasattr(handler, 'retryMax'):
            # default max retry is 30s which seems too much. Let's make it that
            # the pool tries to reconnect to a client every 10s (similar to the
            # tango event reconnection
            handler.retryMax = 10.0
        log.addHandler(handler)
        self.info("Remote logging initialized for host '%s' on port %d",
                  host, port)

    def serialize(self, *args, **kwargs):
        kwargs = PoolObject.serialize(self, *args, **kwargs)
        kwargs['type'] = self.__class__.__name__
        kwargs['id'] = InvalidId
        kwargs['parent'] = None
        return kwargs

    def set_motion_loop_sleep_time(self, motion_loop_sleep_time):
        self._motion_loop_sleep_time = motion_loop_sleep_time

    def get_motion_loop_sleep_time(self):
        return self._motion_loop_sleep_time

    motion_loop_sleep_time = property(get_motion_loop_sleep_time,
                                      set_motion_loop_sleep_time,
                                      doc="motion sleep time (s)")

    def set_motion_loop_states_per_position(self, motion_loop_states_per_position):
        self._motion_loop_states_per_position = motion_loop_states_per_position

    def get_motion_loop_states_per_position(self):
        return self._motion_loop_states_per_position

    motion_loop_states_per_position = property(get_motion_loop_states_per_position,
                                               set_motion_loop_states_per_position,
                                               doc="Number of State reads done before doing a position read in the "
                                               "motion loop")

    def set_acq_loop_sleep_time(self, acq_loop_sleep_time):
        self._acq_loop_sleep_time = acq_loop_sleep_time

    def get_acq_loop_sleep_time(self):
        return self._acq_loop_sleep_time

    acq_loop_sleep_time = property(get_acq_loop_sleep_time,
                                   set_acq_loop_sleep_time,
                                   doc="acquisition sleep time (s)")

    def set_acq_loop_states_per_value(self, acq_loop_states_per_value):
        self._acq_loop_states_per_value = acq_loop_states_per_value

    def get_acq_loop_states_per_value(self):
        return self._acq_loop_states_per_value

    acq_loop_states_per_value = property(get_acq_loop_states_per_value,
                                         set_acq_loop_states_per_value,
                                         doc="Number of State reads done before doing a value read in the "
                                         "acquisition loop")

    def set_drift_correction(self, drift_correction):
        self._drift_correction = drift_correction

    def get_drift_correction(self):
        return self._drift_correction

    drift_correction = property(get_drift_correction,
                                set_drift_correction,
                                doc="drift correction")

    @property
    def monitor(self):
        return self._monitor

    @property
    def ctrl_manager(self):
        return ControllerManager()

    def set_python_path(self, path):
        mod_man = ModuleManager()
        if self._path_id is not None:
            mod_man.remove_python_path(self._path_id)
        self._path_id = mod_man.add_python_path(path)

    def set_path(self, path):
        self.ctrl_manager.setControllerPath(path, reload=False)

    def get_controller_libs(self):
        return self.ctrl_manager.getControllerLibs()

    def get_controller_lib_names(self):
        return self.ctrl_manager.getControllerLibNames()

    def get_controller_class_names(self):
        return self.ctrl_manager.getControllerNames()

    def get_controller_classes(self):
        return self.ctrl_manager.getControllers()

    def get_controller_class_info(self, name):
        return self.ctrl_manager.getControllerMetaClass(name)

    def get_controller_classes_info(self, names):
        return self.ctrl_manager.getControllerMetaClasses(names)

    def get_controller_libs_summary_info(self):
        libs = self.get_controller_libs()
        ret = []
        for ctrl_lib_info in libs:
            elem = "%s (%s)" % (ctrl_lib_info.getName(),
                                ctrl_lib_info.getFileName())
            ret.append(elem)
        return ret

    def get_controller_classes_summary_info(self):
        ctrl_classes = self.get_controller_classes()
        ret = []
        for ctrl_class_info in ctrl_classes:
            types = ctrl_class_info.getTypes()
            types_str = [TYPE_MAP_OBJ[
                t].name for t in types if t != ElementType.Controller]
            types_str = ", ".join(types_str)
            elem = "%s (%s) %s" % (ctrl_class_info.getName(),
                                   ctrl_class_info.getFileName(), types_str)
            ret.append(elem)
        return ret

    def get_elements_str_info(self, obj_type=None):
        if obj_type is None:
            objs = self.get_element_id_map().values()
            objs.extend(self.get_controller_classes())
            objs.extend(self.get_controller_libs())
        elif obj_type == ElementType.ControllerClass:
            objs = self.get_controller_classes()
        elif obj_type == ElementType.ControllerLibrary:
            objs = self.get_controller_libs()
        else:
            objs = self.get_elements_by_type(obj_type)
        name = self.full_name
        return [obj.str(pool=name) for obj in objs]

    def get_elements_info(self, obj_type=None):
        if obj_type is None:
            objs = self.get_element_id_map().values()
            objs.extend(self.get_controller_classes())
            objs.extend(self.get_controller_libs())
            objs.append(self)
        elif obj_type == ElementType.ControllerClass:
            objs = self.get_controller_classes()
        elif obj_type == ElementType.ControllerLibrary:
            objs = self.get_controller_libs()
        else:
            objs = self.get_elements_by_type(obj_type)
        name = self.full_name
        return [obj.serialize(pool=name) for obj in objs]

    def get_acquisition_elements_info(self):
        ret = []
        for _, element in self.get_element_name_map().items():
            if element.get_type() not in TYPE_ACQUIRABLE_ELEMENTS:
                continue
            acq_channel = element.get_default_acquisition_channel()
            full_name = "{0}/{1}".format(element.full_name, acq_channel)
            info = dict(name=element.name, full_name=full_name, origin='local')
            ret.append(info)
        ret.extend(self._extra_acquisition_element_names.values())
        return ret

    def get_acquisition_elements_str_info(self):
        return map(self.str_object, self.get_acquisition_elements_info())

    def create_controller(self, **kwargs):
        ctrl_type = kwargs['type']
        lib = kwargs['library']
        class_name = kwargs['klass']
        name = kwargs['name']
        elem_type = ElementType[ctrl_type]
        mod_name, _ = os.path.splitext(lib)
        kwargs['module'] = mod_name

        td = TYPE_MAP_OBJ[ElementType.Controller]
        klass_map = td.klass
        auto_full_name = td.auto_full_name
        kwargs['full_name'] = full_name = \
            kwargs.get("full_name", auto_full_name.format(**kwargs))
        self.check_element(name, full_name)

        ctrl_class_info = None
        ctrl_lib_info = self.ctrl_manager.getControllerLib(mod_name)
        if ctrl_lib_info is not None:
            ctrl_class_info = ctrl_lib_info.get_controller(class_name)

        kwargs['pool'] = self
        kwargs['class_info'] = ctrl_class_info
        kwargs['lib_info'] = ctrl_lib_info
        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        # For pseudo controllers make sure 'role_ids' is given
        klass = klass_map.get(elem_type, PoolController)
        if elem_type in TYPE_PSEUDO_ELEMENTS:
            motor_roles = kwargs['role_ids']

        # make sure the properties (that may have come from a case insensitive
        # environment like tango) are made case sensitive
        props = {}
        if ctrl_class_info is None:
            ctrl_prop_info = {}
        else:
            ctrl_prop_info = ctrl_class_info.ctrl_properties
        for k, v in kwargs['properties'].items():
            info = ctrl_prop_info.get(k)
            if info is None:
                props[k] = v
            else:
                props[info.name] = v
        kwargs['properties'] = props

        ctrl = klass(**kwargs)
        ret = self.add_element(ctrl)
        self.fire_event(EventType("ElementCreated"), ctrl)
        return ret

    def create_element(self, **kwargs):
        etype = kwargs['type']
        ctrl_id = kwargs['ctrl_id']
        axis = kwargs['axis']
        elem_type = ElementType[etype]
        name = kwargs['name']

        try:
            ctrl = self.get_element(id=ctrl_id)
        except:
            raise Exception("No controller with id '%d' found" % ctrl_id)

        elem_axis = ctrl.get_element(axis=axis)
        if elem_axis is not None:
            raise Exception("Controller already contains axis %d (%s)"
                            % (axis, elem_axis.get_name()))

        kwargs['pool'] = self
        kwargs['ctrl'] = ctrl
        kwargs['ctrl_name'] = ctrl.get_name()

        td = TYPE_MAP_OBJ[elem_type]
        klass = td.klass
        auto_full_name = td.auto_full_name
        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))

        self.check_element(name, full_name)

        if ctrl.is_online():
            ctrl_types, ctrl_id = ctrl.get_ctrl_types(), ctrl.get_id()
            if elem_type not in ctrl_types:
                ctrl_type_str = ElementType.whatis(ctrl_types[0])
                raise Exception("Cannot create %s in %s controller"
                                % (etype, ctrl_type_str))

        # check if controller is online
        # check if axis is allowed
        # create the element in the controller

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)
        elem = klass(**kwargs)
        ctrl.add_element(elem)
        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def create_motor_group(self, **kwargs):
        name = kwargs['name']
        elem_ids = kwargs["user_elements"]

        kwargs['pool'] = self
        kwargs["pool_name"] = self.name
        td = TYPE_MAP_OBJ[ElementType.MotorGroup]
        klass = td.klass
        auto_full_name = td.auto_full_name
        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))
        kwargs.pop('pool_name')

        self.check_element(name, full_name)

        for elem_id in elem_ids:
            elem = self.pool.get_element(id=elem_id)
            if elem.get_type() not in (ElementType.Motor, ElementType.PseudoMotor):
                raise Exception("%s is not a motor" % elem.name)

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        elem = klass(**kwargs)

        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def create_measurement_group(self, **kwargs):
        name = kwargs['name']
        elem_ids = kwargs["user_elements"]

        kwargs['pool'] = self
        kwargs["pool_name"] = self.name

        td = TYPE_MAP_OBJ[ElementType.MeasurementGroup]
        klass = td.klass
        auto_full_name = td.auto_full_name

        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))
        kwargs.pop('pool_name')

        self.check_element(name, full_name)

        for elem_id in elem_ids:
            if isinstance(elem_id, int):
                self.pool.get_element(id=elem_id)
            else:
                tg_attr_validator = TangoAttributeNameValidator()
                params = tg_attr_validator.getParams(elem_id)
                if params is None:
                    raise Exception("Invalid channel name %s" % elem_id)

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        elem = klass(**kwargs)

        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def rename_element(self, old_name, new_name):
        elem = self.get_element_by_name(old_name)
        elem.controller.rename_element(old_name, new_name)
        PoolContainer.rename_element(self, old_name, new_name)
        elem = self.get_element_by_name(new_name)
        self.fire_event(EventType("ElementChanged"), elem)

    def delete_element(self, name):
        try:
            elem = self.get_element(name=name)
        except:
            try:
                elem = self.get_element(full_name=name)
            except:
                raise Exception("There is no element with name '%s'" % name)

        elem_type = elem.get_type()
        if elem_type == ElementType.Controller:
            if len(elem.get_elements()) > 0:
                raise Exception("Cannot delete controller with elements. "
                                "Delete elements first")
        elif elem_type == ElementType.Instrument:
            if elem.has_instruments():
                raise Exception("Cannot delete instrument with instruments. "
                                "Delete instruments first")
            if elem.has_elements():
                raise Exception("Cannot delete instrument with elements")
            parent_instrument = elem.parent_instrument
            if parent_instrument is not None:
                parent_instrument.remove_instrument(elem)
        elif hasattr(elem, "get_controller"):
            ctrl = elem.get_controller()
            ctrl.remove_element(elem)
            instrument = elem.instrument
            if instrument is not None:
                instrument.remove_element(elem)

        self.remove_element(elem)

        self.fire_event(EventType("ElementDeleted"), elem)

    def create_instrument(self, full_name, klass_name, id=None):
        is_root = full_name.count('/') == 1

        if is_root:
            parent_full_name, _ = '', full_name[1:]
            parent = None
        else:
            parent_full_name, _ = full_name.rsplit('/', 1)
            try:
                parent = self.get_element_by_full_name(parent_full_name)
            except:
                raise Exception("No parent instrument named '%s' found"
                                % parent_full_name)
            if parent.get_type() != ElementType.Instrument:
                raise Exception("%s is not an instrument as expected"
                                % parent_full_name)

        self.check_element(full_name, full_name)

        td = TYPE_MAP_OBJ[ElementType.Instrument]
        klass = td.klass

        if id is None:
            id = self.get_new_id()
        else:
            self.reserve_id(id)
        elem = klass(id=id, name=full_name, full_name=full_name,
                     parent=parent, klass=klass_name, pool=self)
        if parent:
            parent.add_instrument(elem)
        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def stop(self):
        msg = ""
        controllers = self.get_elements_by_type(ElementType.Controller)
        for controller in controllers:
            if controller.is_pseudo():
                continue
            elif ElementType.IORegister in controller.get_ctrl_types():
                # Skip IOR since they are not stoppable
                continue
            error_elements = controller.stop_elements()
            if len(error_elements) > 0:
                element_names = ""
                for element in error_elements:
                    element_names += element.name + " "
                msg += ("Controller %s -> %s\n" %
                        (controller.name, element_names))
                self.error("Unable to stop %s controller: "
                           "Stop of elements %s failed" %
                           (controller.name, element_names))
        if msg:
            msg_init = "Elements which could not be stopped:\n"
            raise Exception(msg_init + msg)

    def abort(self):
        msg = ""
        controllers = self.get_elements_by_type(ElementType.Controller)
        for controller in controllers:
            if controller.is_pseudo():
                continue
            elif ElementType.IORegister in controller.get_ctrl_types():
                # Skip IOR since they are not stoppable
                continue
            error_elements = controller.abort_elements()
            if len(error_elements) > 0:
                element_names = ""
                for element in error_elements:
                    element_names += element.name + " "
                msg += ("Controller %s -> %s\n" %
                        (controller.name, element_names))
                self.error("Unable to abort %s controller: "
                           "Abort of elements %s failed" %
                           (controller.name, element_names))
        if msg:
            msg_init = "Elements which could not be aborted:\n"
            raise Exception(msg_init + msg)

    # --------------------------------------------------------------------------
    # (Re)load code
    # --------------------------------------------------------------------------

    def reload_controller_lib(self, lib_name):
        manager = self.ctrl_manager

        old_lib = manager.getControllerLib(lib_name)
        new_elements, changed_elements, deleted_elements = [], [], []
        old_ctrl_classes = ()
        if old_lib is not None:
            ctrl_infos = old_lib.get_controllers()
            pool_ctrls = self.get_elements_by_type(ElementType.Controller)
            init_pool_ctrls = []
            for pool_ctrl in pool_ctrls:
                if pool_ctrl.get_ctrl_info() in ctrl_infos:
                    init_pool_ctrls.append(pool_ctrl)
            old_ctrl_classes = ctrl_infos
            changed_elements.append(old_lib)

        new_lib = manager.reloadControllerLib(lib_name)

        if old_lib is None:
            new_elements.extend(new_lib.get_controllers())
            new_elements.append(new_lib)
        else:
            new_names = set([ctrl.name for ctrl in new_lib.get_controllers()])
            old_names = set([ctrl.name for ctrl in old_lib.get_controllers()])
            changed_names = set.intersection(new_names, old_names)
            deleted_names = old_names.difference(new_names)
            new_names = new_names.difference(old_names)

            for new_name in new_names:
                new_elements.append(new_lib.get_controller(new_name))
            for changed_name in changed_names:
                changed_elements.append(new_lib.get_controller(changed_name))
            for deleted_name in deleted_names:
                deleted_elements.append(old_lib.get_controller(deleted_name))

        evt = {"new": new_elements, "change": changed_elements,
               "del": deleted_elements}

        self.fire_event(EventType("ElementsChanged"), evt)

        if old_lib is not None:
            for pool_ctrl in init_pool_ctrls:
                pool_ctrl.re_init()

    def reload_controller_class(self, class_name):
        ctrl_info = self.ctrl_manager.getControllerMetaClass(class_name)
        lib_name = ctrl_info.module_name
        self.reload_controller_lib(lib_name)

    def get_element_id_graph(self):
        physical_elems_id_map = {}
        elem_type_map = self.get_element_type_map()
        for elem_type in TYPE_PHYSICAL_ELEMENTS:
            physical_elems_id_map.update(elem_type_map[elem_type])
        # TODO

    def _build_element_id_dependencies(self, elem_id, graph=None):
        if graph is None:
            graph = Graph()
        elem = self.get_element_by_id(elem_id)
        if elem.get_id() in graph or elem.get_type() in TYPE_PHYSICAL_ELEMENTS:
            return graph
        graph[elem_id] = list(elem.get_user_element_ids())
        return graph

    def get_moveable_id_graph(self):
        moveable_elems_id_map = {}
        elem_type_map = self.get_element_type_map()
        for elem_type in TYPE_MOVEABLE_ELEMENTS:
            moveable_elems_id_map.update(elem_type_map[elem_type])
        graph = Graph()
        for moveable_id in moveable_elems_id_map:
            self._build_element_id_dependencies(moveable_id, graph)
        return graph

    def _build_element_dependencies(self, elem, graph=None):
        if graph is None:
            graph = Graph()
        if elem.get_id() in graph or elem.get_type() in TYPE_PHYSICAL_ELEMENTS:
            return graph
        graph[elem] = list(elem.get_user_elements())
        return graph

    def get_moveable_graph(self):
        moveable_elems_map = {}
        elem_type_map = self.get_element_type_map()
        for elem_type in TYPE_MOVEABLE_ELEMENTS:
            moveable_elems_map.update(elem_type_map[elem_type])
        graph = Graph()
        for moveable in moveable_elems_map.values():
            self._build_element_dependencies(moveable, graph)
        return graph
Exemple #18
0
class PoolBaseController(PoolBaseElement):
    """Base class for all controllers"""

    def __init__(self, **kwargs):
        self._ctrl = None
        self._ctrl_error = None
        self._element_ids = {}
        self._pending_element_ids = {}
        self._element_axis = {}
        self._pending_element_axis = {}
        self._element_names = CaselessDict()
        self._pending_element_names = CaselessDict()
        self._operator = None
        kwargs['elem_type'] = ElementType.Controller
        super(PoolBaseController, self).__init__(**kwargs)

    def get_ctrl_types(self):
        raise NotImplementedError

    def get_ctrl_type_names(self):
        return list(map(ElementType.whatis, self.get_ctrl_types()))

    def is_online(self):
        return True

    def get_ctrl_error(self):
        return self._ctrl_error

    def get_ctrl_error_str(self):
        """"""
        err = self._ctrl_error
        if err is None:
            return ""
        sio = io.StringIO()
        traceback.print_exception(err[0], err[1], err[2], None, sio)
        s = sio.getvalue()
        sio.close()
        if s[-1:] == "\n":
            s = s[:-1]
        return s

    def add_element(self, elem, propagate=1):
        name, axis, eid = elem.get_name(), elem.get_axis(), elem.get_id()
        if self.is_online():
            try:
                self._ctrl.AddDevice(axis)
            except:
                self.error("Unable to add %s(%s)", name, axis, exc_info=1)
                self._pending_element_ids[eid] = elem
                self._pending_element_axis[axis] = elem
                self._pending_element_names[name] = elem
            self._element_ids[eid] = elem
            self._element_axis[axis] = elem
            self._element_names[name] = elem
        else:
            # TODO: raise exception
            self._pending_element_ids[eid] = elem
            self._pending_element_axis[axis] = elem
            self._pending_element_names[name] = elem
        if propagate:
            elements = self.get_elements()
            elements = [elements[_id].name for _id in sorted(elements)]
            self.fire_event(EventType("elementlist", priority=propagate),
                            elements)

    def remove_element(self, elem, propagate=1):
        name, axis, eid = elem.get_name(), elem.get_axis(), elem.get_id()
        f = eid in self._element_ids
        if not f:
            f = eid in self._pending_element_ids
            if not f:
                raise Exception("element '%s' is not in controller")
            del self._pending_element_ids[eid]
            del self._pending_element_axis[axis]
            del self._pending_element_names[name]
        else:
            del self._element_ids[eid]
            del self._element_axis[axis]
            del self._element_names[name]
            try:
                self._ctrl.DeleteDevice(axis)
            except:
                self.error("Unable to delete %s(%s)", name, axis, exc_info=1)
        if propagate:
            elements = self.get_elements()
            elements = [elements[_id].name for _id in sorted(elements)]
            self.fire_event(EventType("elementlist", priority=propagate),
                            elements)

    def rename_element(self, old_name, new_name, propagate=1):
        """Rename element in the controller.

        :param old_name: old name of the element
        :type old_name: :obj:`str`
        :param new_name: new name of the element
        :type new_name: :obj:`str`
        :param propagate: 0 for not propagating, 1 to propagate,
               2 propagate with priority
        :type propagate: :obj:`int`
        """
        element = self._element_names.pop(old_name, None)
        if element is None:
            raise KeyError('There is no element with name %s' % old_name)
        self._element_names[new_name] = element
        if propagate:
            elements = self.get_elements()
            elements = [elements[_id].name for _id in sorted(elements)]
            self.fire_event(EventType("elementlist", priority=propagate),
                            elements)

    def remove_axis(self, axis, propagate=1):
        f = axis in self._element_axis
        if not f:
            f = axis in self._pending_element_axis
            if not f:
                raise Exception("element '%s' is not in controller")
            elem = self._pending_element_axis[axis]
        else:
            elem = self._element_axis[axis]
        self.remove_element(elem, propagate=propagate)

    def get_elements(self):
        return self._element_ids

    def get_element_ids(self):
        return self._element_ids

    def get_element_axis(self):
        return self._element_axis

    def get_element(self, **kwargs):
        k = kwargs.get('axis')
        if k is None:
            k = kwargs.get('name')
            if k is None:
                k = kwargs.get('id')
                if k is None:
                    raise Exception("Must give either name, id or axis")
                d, pd = self._element_ids, self._pending_element_ids
            else:
                d, pd = self._element_names, self._pending_element_names
        else:
            d, pd = self._element_axis, self._pending_element_axis

        elem = d.get(k)
        if elem is None:
            elem = pd.get(k)
        return elem

    def read_axis_states(self, axes=None):
        """Reads the state for the given axes. If axes is None, reads the
        state of all active axes.

        :param axes: the list of axis to get the state. Default is None meaning
                       all active axis in this controller
        :type axes: seq<int> or None
        :return: a map containing the controller state information for each axis
        :rtype: dict<PoolElement, state info>
        """
        raise NotImplementedError

    def read_axis_values(self, axes=None):
        """Reads the value for the given axes. If axes is None, reads the
        value of all active axes.

        :param axes: the list of axis to get the value. Default is None meaning
                       all active axis in this controller
        :type axes: seq<int> or None
        :return: a map containing the controller value information for each axis
        :rtype: dict<PoolElement, value>
        """
        raise NotImplementedError

    def get_status(self, cache=True, propagate=1):
        """Returns the status for this object. If cache is True (default) it
        returns the current status stored in cache (it will force an update if
        cache is empty). If propagate > 0 and if the status changed since last
        read, it will propagate the status event to all listeners.

        :param cache:
            tells if return value from local cache or update from HW read
            [default: True]
        :type cache: bool
        :param propagate:
            if > 0 propagates the event in case it changed since last HW read.
            Values bigger that mean the event if sent should be a priority event
            [default: 1]
        :type propagate: int
        :return: the current object status
        :rtype: str"""
        if not cache or self._status is None:
            state_info = None
            self._set_state_info(state_info, propagate=propagate)
        return self._status

    _STD_STATUS = '{name} is {state}'

    def calculate_state_info(self, status_info=None):
        """Transforms the given state information. This specific base
        implementation transforms the given state,status tuple into a
        state, new_status tuple where new_status is "*self.name* is *state*.

        :param status_info:
            given status information [default: None, meaning use current state status.
        :type status_info: tuple<State, str>
        :return: a transformed state information
        :rtype: tuple<State, str>"""
        if status_info is None:
            status_info = self._state, self._status
        state, _ = status_info
        state_str = State[state]
        new_status = self._STD_STATUS.format(name=self.name, state=state_str)
        return status_info[0], new_status
Exemple #19
0
class TangoFactory(Singleton, TaurusFactory, Logger):
    """A :class:`TaurusFactory` singleton class to provide Tango-specific
    Taurus Element objects (TangoAuthority, TangoDevice, TangoAttribute)

    Tango model names are URI based See https://tools.ietf.org/html/rfc3986.
    For example, a TangoAttribute would be::

        tango://foo.org:1234/a/b/c/d#label
        \___/   \_____/ \__/ \_____/ \___/
          |        |     |      |      |
          |    hostname port  attr     |
          |   \____________/\______/   |
          |         |           |      |
        scheme   authority     path  fragment

    For Tango Elements:

        - The 'scheme' must be the string "tango" (lowercase mandatory)
        - The 'authority' identifies the Tango database (<hostname> and <port>
          are mandatory if authority is given)
        - The 'path' identifies Tango Device and Attributes.
          For devices it must have the format _/_/_ or alias
          For attributes it must have the format _/_/_/_ or devalias/_
        - The 'fragment' is optional and it refers to a member of the model
          object, thus not being part of the model name itself
    """

    #: the list of schemes that this factory supports. For this factory: 'tango'
    #: is the only scheme
    schemes = ("tango", )
    caseSensitive = False
    elementTypesMap = {
        TaurusElementType.Authority: TangoAuthority,
        TaurusElementType.Device: TangoDevice,
        TaurusElementType.Attribute: TangoAttribute
    }

    def __init__(self):
        """ Initialization. Nothing to be done here for now."""
        pass

    def init(self, *args, **kwargs):
        """Singleton instance initialization.
           **For internal usage only**"""
        name = self.__class__.__name__
        self.call__init__(Logger, name)
        self.call__init__(TaurusFactory)
        self._polling_enabled = True
        self.reInit()
        self.scheme = 'tango'

    def reInit(self):
        """Reinitialize the singleton"""
        self._default_tango_host = None
        self.dft_db = None
        self.tango_db = CaselessWeakValueDict()
        self.tango_db_queries = CaselessWeakValueDict()
        self.tango_attrs = CaselessWeakValueDict()
        self.tango_devs = CaselessWeakValueDict()
        self.tango_dev_queries = CaselessWeakValueDict()
        self.tango_alias_devs = CaselessWeakValueDict()
        self.polling_timers = {}

        # Plugin device classes
        self.tango_dev_klasses = {}

        # Plugin attribute classes
        self.tango_attr_klasses = CaselessDict()

    def cleanUp(self):
        """Cleanup the singleton instance"""
        self.trace("[TangoFactory] cleanUp")
        for k, v in self.tango_attrs.items():
            v.cleanUp()
        for k, v in self.tango_dev_queries.items():
            v.cleanUp()
        for k, v in self.tango_devs.items():
            v.cleanUp()
        self.dft_db = None
        for k, v in self.tango_db_queries.items():
            v.cleanUp()
        for k, v in self.tango_db.items():
            v.cleanUp()
        self.reInit()

    def getExistingAttributes(self):
        """Returns a new dictionary will all registered attributes on this factory

           :return:  dictionary will all registered attributes on this factory
           :rtype: dict"""
        return dict(self.tango_attrs)

    def getExistingDevices(self):
        """Returns a new dictionary will all registered devices on this factory

           :return:  dictionary will all registered devices on this factory
           :rtype: dict"""
        return dict(self.tango_devs)

    def getExistingDatabases(self):
        """Returns a new dictionary will all registered databases on this factory

           :return:  dictionary will all registered databases on this factory
           :rtype: dict"""
        return dict(self.tango_db)

    def set_default_tango_host(self, tango_host):
        """Sets the new default tango host.

        :param tango_host: (str) the new tango host
        """
        self._default_tango_host = tango_host
        self.dft_db = None

    def registerAttributeClass(self, attr_name, attr_klass):
        """Registers a new attribute class for the attribute name.

           :param attr_name: (str) attribute name
           :param attr_klass: (taurus.core.tango.TangoAttribute) the new class that
                              will handle the attribute
        """
        self.tango_attr_klasses[attr_name] = attr_klass

    def unregisterAttributeClass(self, attr_name):
        """Unregisters the attribute class for the given attribute
           If no class was registered before for the given attribute, this call
           as no effect

           :param attr_name: (str) attribute name
        """
        if self.tango_attr_klasses.has_key(attr_name):
            del self.tango_attr_klasses[attr_name]

    def registerDeviceClass(self, dev_klass_name, dev_klass):
        """Registers a new python class to handle tango devices of the given tango class name

           :param dev_klass_name: (str) tango device class name
           :param dev_klass: (taurus.core.tango.TangoDevice) the new class that will
                             handle devices of the given tango class name
        """
        self.tango_dev_klasses[dev_klass_name] = dev_klass

    def unregisterDeviceClass(self, dev_klass_name):
        """Unregisters the class for the given tango class name
           If no class was registered before for the given attribute, this call
           as no effect

           :param dev_klass_name: (str) tango device class name
        """
        if self.tango_dev_klasses.has_key(dev_klass_name):
            del self.tango_dev_klasses[dev_klass_name]

    def getDatabase(self, name=None):
        '''Deprecated. Use getAuthority instead'''
        return self.getAuthority(name=name)

    def getAuthority(self, name=None):
        """
        Obtain the object corresponding to the given database name or the
        default database if name is None.
        If the corresponding authority object already exists, the existing
        instance is returned. Otherwise a new instance is stored and returned.

        :param name: (str) database name string alias. If None, the
                        default database is used

        :return: (taurus.core.tangodatabase.TangoAuthority) database object
        :raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid.
        """
        ret = None
        if name is None:
            if self.dft_db is None:
                try:
                    if self._default_tango_host is None:
                        self.dft_db = _Authority()
                    else:
                        name = self._default_tango_host
                        validator = _Authority.getNameValidator()
                        groups = validator.getUriGroups(name)
                        if groups is None:
                            raise TaurusException(
                                "Invalid default Tango authority name %s" %
                                name)
                        self.dft_db = _Authority(host=groups['host'],
                                                 port=groups['port'])
                except:
                    self.debug("Could not create Authority", exc_info=1)
                    raise
                name = self.dft_db.getFullName()
                self.tango_db[name] = self.dft_db
            ret = self.dft_db
        else:
            ret = self.tango_db.get(name)
            if not ret is None:
                return ret
            validator = _Authority.getNameValidator()
            groups = validator.getUriGroups(name)
            if not validator.isValid(name):
                raise TaurusException("Invalid Tango authority name %s" % name)
            try:
                ret = _Authority(host=groups['host'], port=groups['port'])
            except:
                self.debug("Could not create Authority %s",
                           groups['authority'],
                           exc_info=1)

            self.tango_db[name] = ret
        return ret

    def getDevice(self, dev_name, create_if_needed=True, **kw):
        """Obtain the object corresponding to the given tango device name.
           If the corresponding device already exists, the existing instance
           is returned. Otherwise a new instance is stored and returned.

           :param dev_name: (str) tango device name or tango alias for the
                            device. It must be a valid Tango device URI.
                            If authority is not explicit, the default Tango
                            Database will be used
           :param create_if_needed: (bool) If True, the Device is created if it
                                    did not exist previously. If False, it
                                    returns None if it did not exist

           :return: (taurus.core.tango.TangoDevice) a device object
           :raise: (taurus.core.taurusexception.TaurusException) if the given
                   dev_name is invalid.
        """
        d = self.tango_devs.get(dev_name)
        if d is None:
            d = self.tango_alias_devs.get(dev_name)
        if d is not None:
            return d

        validator = _Device.getNameValidator()
        groups = validator.getUriGroups(dev_name)
        if groups is None:
            raise TaurusException("Invalid Tango device name '%s'" % dev_name)

        full_dev_name, _, _ = validator.getNames(dev_name)

        if full_dev_name is None:
            raise TaurusException("Cannot find full name of '%s'" % dev_name)

        d = self.tango_devs.get(full_dev_name)

        if not create_if_needed:
            return d

        if d is None:
            try:
                db = self.getAuthority(groups.get('authority'))
                dev_klass = self._getDeviceClass(db=db,
                                                 devname=groups['devname'])
                kw['storeCallback'] = self._storeDevice
                kw['parent'] = db
                d = dev_klass(full_dev_name, **kw)
                # device objects will register themselves in this factory
                # so there is no need to do it here
            except DoubleRegistration:
                d = self.tango_devs.get(full_dev_name)
            except:
                self.debug("Error creating device %s", dev_name, exc_info=1)
                raise
        return d

    def getAttribute(self, attr_name, create_if_needed=True, **kwargs):
        """Obtain the object corresponding to the given attribute name.
           If the corresponding attribute already exists, the existing instance
           is returned. Otherwise a new instance is stored and returned.

           :param attr_name: (str) a valid attribute name URI
           :param create_if_needed: (bool) If True, the Attribute is created if
                                    it did not already exist. If False,
                                    None is returned if it did not exist
           :return: (taurus.core.tangoattribute.TangoAttribute) attribute object
           :raise: (taurus.core.taurusexception.TaurusException) if the given
                   alias is invalid.
        """
        attr = self.tango_attrs.get(attr_name)
        if attr is not None:
            return attr

        # Simple approach did not work. Lets build a proper device name
        validator = _Attribute.getNameValidator()
        groups = validator.getUriGroups(attr_name)
        if groups is None:
            raise TaurusException(
                ("Invalid Tango attribute name '%s'") % attr_name)

        full_attr_name, _, _ = validator.getNames(attr_name)

        if full_attr_name is None:
            raise TaurusException("Cannot find full name of '%s'" % attr_name)

        attr = self.tango_attrs.get(full_attr_name)

        if attr is None:
            dev_name = full_attr_name.rsplit('/', 1)[0]
            try:
                dev = self.getDevice(dev_name)
                if dev is not None:
                    # Do another try in case the Device object created the attribute
                    # itself. This happens for the 'state' attribute
                    attr = self.tango_attrs.get(full_attr_name)
                    if attr is not None:
                        return attr
                    try:
                        attr_klass = self._getAttributeClass(
                            attr_name=attr_name)
                        kwargs['storeCallback'] = self._storeAttribute
                        if not kwargs.has_key('pollingPeriod'):
                            kwargs[
                                'pollingPeriod'] = self.getDefaultPollingPeriod(
                                )
                        attr = attr_klass(full_attr_name, dev, **kwargs)
                        # attribute objects will register themselves in this factory
                        # so there is no need to do it here
                    except DoubleRegistration:
                        attr = self.tango_attrs.get(full_attr_name)
            except:
                self.debug("Error creating attribute %s",
                           attr_name,
                           exc_info=1)
                raise
        return attr

    def getAttributeInfo(self, full_attr_name):
        """Deprecated: Use :meth:`taurus.core.tango.TangoFactory.getConfiguration` instead.

           Obtain attribute information corresponding to the given attribute name.
           If the corresponding attribute info already exists, the existing information
           is returned. Otherwise a new information instance is stored and returned.

           :param full_attr_name: (str) attribute name in format: <tango device name>'/'<attribute name>

           :return: (taurus.core.tango.TangoConfiguration) configuration object
        """
        self.deprecated("Use getConfiguration(full_attr_name) instead")
        attr = self.getAttribute(full_attr_name)
        return attr

    @taurus4_deprecation(alt='getAttribute')
    def getConfiguration(self, param):
        """Obtain the object corresponding to the given attribute or full name.
           If the corresponding configuration already exists, the existing instance
           is returned. Otherwise a new instance is stored and returned.

           :param param: (taurus.core.taurusattribute.TaurusAttribute or str)
                         attribute object or full configuration name

           :return: (taurus.core.tango.TangoAttribute) configuration object
        """
        if isinstance(param, str):
            return self.getAttribute(param)
        return param

    def _getAttributeClass(self, **params):
        attr_name = params.get("attr_name")
        attr_klass = self.tango_attr_klasses.get(attr_name, _Attribute)
        return attr_klass

    def _getDeviceClass(self, **kwargs):
        db, dev_name = kwargs.get("db"), kwargs.get("devname")
        if db is None or dev_name is None or len(self.tango_dev_klasses) == 0:
            return _Device
        else:
            if '/' not in dev_name:  # we got an alias... find the devslashname
                dev_name = db.getElementFullName(dev_name)
            tango_dev_klass = db.get_class_for_device(dev_name)
            return self.tango_dev_klasses.get(tango_dev_klass, _Device)

    def _storeDevice(self, dev):
        name, alias = dev.getFullName(), dev.getSimpleName()
        exists = self.tango_devs.get(name)
        if not exists is None:
            if exists == dev:
                msg = "%s has already been registered before" % name
            else:
                msg = "%s has already been registered before with a different object!" % name
            self.debug(msg)
            raise DoubleRegistration(msg)
        self.tango_devs[name] = dev
        if not alias is None and len(alias):
            self.tango_alias_devs[alias] = dev

    def _storeAttribute(self, attr):
        name = attr.getFullName()
        exists = self.tango_attrs.get(name)
        if not exists is None:
            if exists == attr:
                msg = "%s has already been registered before" % name
            else:
                msg = "%s has already been registered before with a different object!" % name
            self.debug(msg)
            raise DoubleRegistration(msg)
        self.tango_attrs[name] = attr

    def getExistingAttribute(self, attr_name):
        """Deprecated: use getAtribute with create_if_needed=False
        """
        self.warning(('getExistingAttribute is deprecated. ' +
                      'Use getDevice with create_if_needed=False'))
        return self.getAttribute(attr_name, create_if_needed=False)

    def getExistingDevice(self, dev_name):
        """Deprecated: use getDevice with create_if_needed=False
        """
        self.warning(('getExistingDevice is deprecated. ' +
                      'Use getDevice with create_if_needed=False'))
        return self.getDevice(dev_name, create_if_needed=False)

    def removeExistingDevice(self, dev_or_dev_name):
        """Removes a previously registered device.

           :param dev_or_dev_name: (str or TangoDevice) device name or device object
        """
        if isinstance(dev_or_dev_name, _Device):
            dev = dev_or_dev_name
        else:
            dev = self.getDevice(dev_or_dev_name, create_if_needed=False)
        if dev is None:
            raise KeyError("Device %s not found" % dev_or_dev_name)
        dev.cleanUp()
        full_name = dev.getFullName()
        if self.tango_devs.has_key(full_name):
            del self.tango_devs[full_name]
        simp_name = dev.getSimpleName()
        if self.tango_alias_devs.has_key(simp_name):
            del self.tango_alias_devs[simp_name]

    def removeExistingAttribute(self, attr_or_attr_name):
        """Removes a previously registered attribute.

           :param attr_or_attr_name: (str or TangoAttribute) attribute name or attribute object
        """
        if isinstance(attr_or_attr_name, _Attribute):
            attr = attr_or_attr_name
        else:
            attr = self.getExistingAttribute(attr_or_attr_name)
        if attr is None:
            raise KeyError("Attribute %s not found" % attr_or_attr_name)
        attr.cleanUp()
        full_name = attr.getFullName()
        if self.tango_attrs.has_key(full_name):
            del self.tango_attrs[full_name]

    def addAttributeToPolling(self, attribute, period, unsubscribe_evts=False):
        """Activates the polling (client side) for the given attribute with the
           given period (seconds).

           :param attribute: (taurus.core.tango.TangoAttribute) attribute name.
           :param period: (float) polling period (in seconds)
           :param unsubscribe_evts: (bool) whether or not to unsubscribe from events
        """
        tmr = self.polling_timers.get(period, TaurusPollingTimer(period))
        self.polling_timers[period] = tmr
        tmr.addAttribute(attribute, self.isPollingEnabled())

    def removeAttributeFromPolling(self, attribute):
        """Deactivate the polling (client side) for the given attribute. If the
           polling of the attribute was not previously enabled, nothing happens.

           :param attribute: (str) attribute name.
        """
        p = None
        for period, timer in self.polling_timers.iteritems():
            if timer.containsAttribute(attribute):
                timer.removeAttribute(attribute)
                if timer.getAttributeCount() == 0:
                    p = period
                break
        if p:
            del self.polling_timers[period]

    def isPollingEnabled(self):
        """Tells if the local tango polling is enabled

           :return: (bool) wheter or not the polling is enabled
        """
        return self._polling_enabled

    def disablePolling(self):
        """Disable the application tango polling"""
        if not self.isPollingEnabled():
            return
        self._polling_enabled = False
        for period, timer in self.polling_timers.iteritems():
            timer.stop()

    def enablePolling(self):
        """Enable the application tango polling"""
        if self.isPollingEnabled():
            return
        for period, timer in self.polling_timers.iteritems():
            timer.start()
        self._polling_enabled = True

    def getDatabaseNameValidator(self):
        """Deprecated"""
        self.warning(('getDatabaseNameValidator is deprecated.' +
                      'Use "Authority" instead of "Database"'))
        return self.getAuthorityNameValidator()

    def getAuthorityNameValidator(self):
        """Return TangoAuthorityNameValidator"""
        import tangovalidator
        return tangovalidator.TangoAuthorityNameValidator()

    def getDeviceNameValidator(self):
        """Return TangoDeviceNameValidator"""
        import tangovalidator
        return tangovalidator.TangoDeviceNameValidator()

    def getAttributeNameValidator(self):
        """Return TangoAttributeNameValidator"""
        import tangovalidator
        return tangovalidator.TangoAttributeNameValidator()

    def setOperationMode(self, mode):
        """ Deprecated. setOperationMode(OperationMode mode) -> None
            Sets the operation mode for the Tango system."""
        dep = 'setOperationMode'
        rel = 'Taurus4'
        dbg_msg = "Don't use this method"
        msg = '%s is deprecated (from %s). %s' % (dep, rel, dbg_msg)
        self.deprecated(msg)

    def getOperationMode(self):
        """Deprecated. Gives the current operation mode."""
        dep = 'getOperationMode'
        rel = 'Taurus4'
        dbg_msg = "Don't use this method"
        msg = '%s is deprecated (from %s). %s' % (dep, rel, dbg_msg)
        self.deprecated(msg)
        return OperationMode.ONLINE
Exemple #20
0
 def getElementsWithInterfaces(self, interfaces):
     ret = CaselessDict()
     for interface in interfaces:
         ret.update(self.getElementsWithInterface(interface))
     return ret
    def __init__(
        self,
        parent=None,
        curvePropDict=None,
        showButtons=False,
        autoApply=False,
        curvesDict=None,
        plotItem=None,
        Y2Axis=None,
    ):
        super(CurvesAppearanceChooser, self).__init__(parent)
        self.loadUi()
        self.autoApply = autoApply
        self._curvesDict = curvesDict
        self.plotItem = plotItem
        self.Y2Axis = Y2Axis

        self.sStyleCB.insertItems(0, sorted(NamedSymbolStyles.values()))
        self.lStyleCB.insertItems(0, list(NamedLineStyles.values()))
        self.cStyleCB.insertItems(0, list(NamedCurveStyles.values()))
        self.sColorCB.addItem("")
        self.lColorCB.addItem("")
        self.cAreaDSB.setRange(float("-inf"), float("inf"))
        if not showButtons:
            self.applyBT.hide()
            self.resetBT.hide()
        for color in CURVE_COLORS:
            icon = self._colorIcon(color)
            self.sColorCB.addItem(icon, "", Qt.QColor(color))
            self.lColorCB.addItem(icon, "", Qt.QColor(color))
        self.__itemsDict = CaselessDict()
        self.setCurvesProps(curvePropDict)

        if self.plotItem is None:
            self.bckgndBT.setVisible(False)

        # connections.
        self.curvesLW.itemSelectionChanged.connect(
            self._onSelectedCurveChanged)
        self.curvesLW.itemChanged.connect(self._onItemChanged)
        self.applyBT.clicked.connect(self.onApply)
        self.resetBT.clicked.connect(self.onReset)
        self.sStyleCB.currentIndexChanged.connect(self._onSymbolStyleChanged)

        self.sStyleCB.currentIndexChanged.connect(self._onControlChanged)
        self.lStyleCB.currentIndexChanged.connect(self._onControlChanged)
        self.sColorCB.currentIndexChanged.connect(self._onControlChanged)
        self.lColorCB.currentIndexChanged.connect(self._onControlChanged)
        self.cStyleCB.currentIndexChanged.connect(self._onControlChanged)
        self.sSizeSB.valueChanged.connect(self._onControlChanged)
        self.lWidthSB.valueChanged.connect(self._onControlChanged)
        self.cAreaDSB.valueChanged.connect(self._onControlChanged)
        self.sFillCB.stateChanged.connect(self._onControlChanged)
        self.cFillCB.stateChanged.connect(self._onControlChanged)

        self.assignToY1BT.toggled[bool].connect(self.__onY1Toggled)
        self.assignToY2BT.toggled[bool].connect(self.__onY2Toggled)

        self.bckgndBT.clicked.connect(self.changeBackgroundColor)

        # Disabled button until future implementations
        self.changeTitlesBT.setEnabled(False)

        # disable the group box with the options for swap curves between Y axes
        if Y2Axis is None or plotItem is None:
            self.groupBox.setEnabled(False)

        self._onSelectedCurveChanged()
        self.axis = None
Exemple #22
0
    def __init__(self, container, name=None, full_name=None):
        super(TangoDevClassInfo, self).__init__(container, name=name,
                                                full_name=full_name)

        self._devices = CaselessDict()
Exemple #23
0
class EnvironmentManager(MacroServerManager):
    """The MacroServer environment manager class. It is designed to be a
    singleton for the entire application.
    """

    def __init__(self, macro_server, environment_db=None):
        MacroServerManager.__init__(self, macro_server)
        if environment_db is not None:
            self.setEnvironmentDb(environment_db)

    def reInit(self):
        """(Re)initializes the manager"""
        if self.is_initialized():
            return

        # a string containing the absolute filename containing the environment
        self._env_name = None

        # the full enviroment (a shelf for now - can be accessed as a dict)
        self._env = None

        # cache environment for keys that start with door name
        # dict<string, dict<string, value> > where:
        #  - key: door name
        #  - value: dict where:
        #    - key: environment name
        #    - value: environment value
        self._door_env = None

        # cache environment for keys that start with macro name
        # dict<string, dict<string, value> > where:
        #  - key: macro name
        #  - value: dict where:
        #    - key: environment name
        #    - value: environment value
        self._macro_env = None

        # cache environment for global keys
        # dict<string, value> where:
        #  - key: environment name
        #  - value: environment value
        self._global_env = None

        self._initEnv()

        MacroServerManager.reInit(self)

    def cleanUp(self):
        if self.is_cleaned():
            return

        self._clearEnv()

        MacroServerManager.cleanUp(self)

    def _initEnv(self):
        self._macro_env, self._global_env = {}, {}
        self._door_env = CaselessDict()

    def _clearEnv(self):
        self._env = self._macro_env = self._global_env = self._door_env = None

    def setEnvironmentDb(self, f_name):
        """Sets up a new environment from a file"""
        self._initEnv()
        f_name = os.path.abspath(f_name)
        self._env_name = f_name
        dir_name = os.path.dirname(f_name)
        if not os.path.isdir(dir_name):
            try:
                self.info("Creating environment directory: %s" % dir_name)
                os.makedirs(dir_name)
            except OSError as ose:
                self.error("Creating environment: %s" % ose.strerror)
                self.debug("Details:", exc_info=1)
                raise ose
        if os.path.exists(f_name) or os.path.exists(f_name + ".dat"):
            try:
                self._env = shelve.open(f_name, flag='w', writeback=False)
            except Exception:
                self.error("Failed to access environment in %s", f_name)
                self.debug("Details:", exc_info=1)
                raise
        else:
            backend = getattr(sardanacustomsettings, "MS_ENV_SHELVE_BACKEND",
                              None)
            try:
                self._env = shelve.Shelf(_dbm_shelve(f_name, backend))
            except Exception:
                self.error("Failed to create environment in %s", f_name)
                self.debug("Details:", exc_info=1)
                raise

        self.info("Environment is being stored in %s", f_name)

        # fill the three environment caches
        try:
            self._fillEnvironmentCaches(self._env)
        except:
            self.error("Failed to fill local enviroment cache")
            self.debug("Details:", exc_info=1)

    def _fillEnvironmentCaches(self, env):
        # fill the three environment caches
        env_dict = self._global_env
        for k, v in list(env.items()):
            k_parts = k.split('.', 1)
            key = k_parts[0]

            # door or macro property
            if len(k_parts) == 2:
                obj_name, simple_key_name = k_parts
                if obj_name.count('/') == 2:
                    class_dict = self._door_env
                else:
                    class_dict = self._macro_env
                obj_dict = class_dict.get(obj_name, None)
                if obj_dict is None:
                    class_dict[obj_name] = obj_dict = {}
                obj_dict[simple_key_name] = v
            else:
                env_dict[key] = v

    def hasEnv(self, key, macro_name=None, door_name=None):
        #<door>.<macro>.<property name> (highest priority)
        if macro_name and door_name:
            has = self._hasDoorMacroPropertyEnv((door_name, macro_name, key))
            if has:
                return True

        # <macro>.<property name>
        if macro_name:
            has = self._hasMacroPropertyEnv((macro_name, key))
            if has:
                return True

        # <door>.<property name>
        if door_name:
            has = self._hasDoorPropertyEnv((door_name, key))
            if has:
                return True

        # <property name> (less priority)
        return self._hasEnv(key)

    def _getDoorMacroPropertyEnv(self, prop):
        """Returns the property value for a property which must have the
        format <door name>.<macro name>.<property name>"""
        if isinstance(prop, str):
            door_name, macro_name_key = prop.split('.', 1)
        else:
            door_name, macro_name_key = prop[0], '.'.join(prop[1:])
        door_props = self._door_env.get(door_name)
        if door_props is None:
            return None
        return door_props.get(macro_name_key)

    def _hasDoorMacroPropertyEnv(self, prop):
        """Determines if the environment contains a property with the format
        <door name>.<macro name>.<property name>"""
        return not self._getDoorMacroPropertyEnv(prop) is None

    def _getMacroPropertyEnv(self, prop):
        """Returns the property value for a property which must have the
        format <macro name>.<property name>"""
        if isinstance(prop, str):
            macro_name, key = prop.split('.')
        else:
            macro_name, key = prop
        macro_props = self._macro_env.get(macro_name)
        if macro_props is None:
            return None
        return macro_props.get(key)

    def _hasMacroPropertyEnv(self, prop):
        """Determines if the environment contains a property with the format
        <macro name>.<property name>"""
        return not self._getMacroPropertyEnv(prop) is None

    def _getDoorPropertyEnv(self, prop):
        """Returns the property value for a property which must have the
        format <door name>.<property name>"""
        if isinstance(prop, str):
            door_name, key = prop.split('.')
        else:
            door_name, key = prop
        door_props = self._door_env.get(door_name)
        if door_props is None:
            return None
        return door_props.get(key)

    def _hasDoorPropertyEnv(self, prop):
        """Determines if the environment contains a property with the format
        <door name>.<property name>"""
        return not self._getDoorPropertyEnv(prop) is None

    def _getEnv(self, prop):
        """Returns the property value for a property which must have the
        format <property name>"""
        return self._global_env.get(prop)

    def _hasEnv(self, prop):
        """Determines if the environment contains a property with the format
        <property name>"""
        return not self._getEnv(prop) is None

    def getEnv(self, key=None, door_name=None, macro_name=None):
        """Gets the environment matching the given parameters:
        - If key is None it returns the complete environment for the given
          macro and/or door. If both are None the the complete environment is
          returned
          @param[in]"""
        if key is None:
            return self._getAllEnv(door_name=door_name, macro_name=macro_name)

        #<door>.<macro>.<property name> (highest priority)
        if macro_name and door_name:
            v = self._getDoorMacroPropertyEnv((door_name, macro_name, key))
            if not v is None:
                return v

        # <macro>.<property name>
        if macro_name:
            v = self._getMacroPropertyEnv((macro_name, key))
            if not v is None:
                return v

        # <door>.<property name>
        if door_name:
            v = self._getDoorPropertyEnv((door_name, key))
            if not v is None:
                return v

        # <property name> (less priority)
        v = self._getEnv(key)
        if v is None:
            raise UnknownEnv("Unknown environment %s" % key)
        return v

    def _getAllEnv(self, door_name=None, macro_name=None):
        """Gets the complete environment for the given macro and/or door. If
        both are None the the complete environment is returned"""
        if macro_name is None and door_name is None:
            return dict(self._env)
        elif not door_name is None and macro_name is None:
            return self.getDoorEnv(door_name)
        elif door_name and macro_name:
            return self.getAllDoorMacroEnv(door_name, macro_name)
        elif not macro_name is None and door_name is None:
            return self._macro_env.get(macro_name, {})

    def getAllDoorEnv(self, door_name):
        """Gets the complete environment for the given door."""
        door_name = door_name.lower()

        # first go through the global environment
        ret = self._global_env.copy()

        # Then go through the door specific environment
        ret.update(self._door_env.get(door_name, {}))
        return ret

    def getAllDoorMacroEnv(self, door_name, macro_name):
        """Gets the complete environment for the given macro in a specific
        door.

        :param door_name:  the door name (case insensitive)
        :type door_name: :obj:`str`
        :param macro_name: the macro name
        :type macro_name: :obj:`str`

        :return: a dictionary with the resulting environment"""
        door_name = door_name.lower()

        # first go through the global environment
        ret = self._global_env.copy()

        # get the specific door environment
        d_env = self._door_env.get(door_name, {})

        # get the specific macro environment
        m_env = self._macro_env.get(macro_name, {})

        # put the doors global environment
        for k, v in d_env.items():
            if k.count('.') == 0:
                ret[k] = v

        # put the macro environment
        ret.update(m_env)

        # put the door and macro specific environment
        for k, v in d_env.items():
            if k.count('.') > 0:
                m_name, key = k.split('.', 1)
                if m_name is macro_name:
                    ret[key] = v

        return ret

    def getDoorMacroEnv(self, door_name, macro_name, keys=None):
        """Gets the environment for the given macro in a specific door for the
        given key(s)

        :param door_name: the door name (case insensitive)
        :param macro_name: the macro name (case sensitive)
        :param key: the keys to be retrieved. If None (default) the complete
                    environment is returned (same as getAllDoorMacroEnv)
                    key can be a string or a sequence<string>.
                    keys must NOT contain '.' characters

        :return: a dictionary with the resulting environment"""
        if keys is None:
            return self.getAllDoorMacroEnv(door_name, macro_name)

        if isinstance(keys, str):
            keys = (keys,)

        door_name = door_name.lower()

        g_env = self._global_env
        # get the specific door environment
        d_env = self._door_env.get(door_name, {})
        # get the specific macro environment
        m_env = self._macro_env.get(macro_name, {})

        # first go through the global environment
        ret = {}
        for k in keys:
            comp_key = '%s.%s' % (macro_name, k)
            if comp_key in d_env:
                ret[k] = d_env[comp_key]
            elif k in m_env:
                ret[k] = m_env[k]
            elif k in d_env:
                ret[k] = d_env[k]
            elif k in g_env:
                ret[k] = g_env[k]

        return ret

    def _grouper(self, iterable):
        # https://docs.python.org/3/library/itertools.html#itertools-recipes
        args = [iter(iterable)] * 2
        return zip_longest(*args)

    def _dictFromSequence(self, seq):
        return dict(self._grouper(seq))

    def _encode(self, d):
        ret = {}
        for k, v in d.items():
            if isinstance(v, str):
                try:
                    v = eval(v)
                except:
                    v_lower = v.lower()
                    try:
                        v = eval(v_lower.capitalize())
                    except:
                        pass
            ret[k] = v
        return ret

    def _getCacheForKey(self, key):
        """Returns the cache dictionary object for the given key

        :param key: a string representing the key
        :return: a tuple pair. The first element is the dictionary and the
                 second is the modified key that is applicable to the
                 dictionary"""
        d = None
        key_parts = key.split('.')
        # global property
        if len(key_parts) == 1:
            d = self._global_env
        # macro property
        elif len(key_parts) == 2 and key_parts[0].count('/') != 2:
            macro_name, key = key_parts
            d = self._macro_env.get(macro_name)
            if d is None:
                self._macro_env[macro_name] = d = {}
        # door property
        else:
            door_name, key = key.split('.', 1)
            d = self._door_env.get(door_name)
            if d is None:
                self._door_env[door_name] = d = {}
        return d, key

    def _setOneEnv(self, key, value):
        self._env[key] = value
        self._env.sync()
        d, key = self._getCacheForKey(key)
        d[key] = value

    def _unsetOneEnv(self, key):
        if key not in self._env:
            raise UnknownEnv("Unknown environment %s" % key)
        del self._env[key]
        self._env.sync()
        d, key = self._getCacheForKey(key)
        if key in d:
            del d[key]

    def _unsetEnv(self, env_names):
        for key in env_names:
            self._unsetOneEnv(key)

    def setEnvObj(self, obj):
        """Sets the environment for the given object. If object is a sequence
        then each pair of elements k, v is added as env[k] = v.
        If object is a map then the environmnent is updated.
        Other object types are not supported
        The elements which are strings are 'python evaluated'

        @throws TypeError is obj is not a sequence or a map

        @param[in] obj object to be added to the environment

        @return a dict representing the added environment"""

        if isinstance(obj, collections.Sequence) and \
           not isinstance(obj, str):
            obj = self._dictFromSequence(obj)
        elif not isinstance(obj, collections.Mapping):
            raise TypeError("obj parameter must be a sequence or a map")

        obj = self._encode(obj)
        for k, v in obj.items():
            self._setOneEnv(k, v)
        return obj

    def setEnv(self, key, value):
        """Sets the environment key to the new value and stores it
        persistently.

        :param key: the key for the environment
        :param value: the value for the environment

        :return: a tuple with the key and value objects stored"""
        ret = self.setEnvObj((key, value))
        return key, ret[key]

    def unsetEnv(self, key):
        """Unsets the environment for the given key.

        :param key: the key for the environment to be unset
        :return: the sequence of keys which have been removed"""
        if isinstance(key, str):
            key = (key,)
        self._unsetEnv(key)
        return key
Exemple #24
0
 def __init__(self, name, image_name='image', **kw):
     self._image_data = CaselessDict()
     self.call__init__(ImageDevice, name, **kw)
     self._image_id_attr = self.getAttribute(self.getImageIDAttrName())
     self._image_id_attr.addListener(self)
    def __init__(self, parent=None, curvePropDict={}, showButtons=False,
                 autoApply=False, Y2Axis=None, curvePropAdapter=None):
        # try:
        super(CurvesAppearanceChooser, self).__init__(parent)
        self.loadUi()
        self.autoApply = autoApply
        self.sStyleCB.insertItems(0, sorted(NamedSymbolStyles.values()))
        self.lStyleCB.insertItems(0, list(NamedLineStyles.values()))
        self.cStyleCB.insertItems(0, list(NamedCurveStyles.values()))
        self.sColorCB.addItem("")
        self.lColorCB.addItem("")
        if not showButtons:
            self.applyBT.hide()
            self.resetBT.hide()
        for color in NamedColors:
            icon = self._colorIcon(color)
            self.sColorCB.addItem(icon, "", Qt.QColor(color))
            self.lColorCB.addItem(icon, "", Qt.QColor(color))
        self.__itemsDict = CaselessDict()
        self.setCurves(curvePropDict)
        # set the icon for the background button (stupid designer limitations
        # forces to do it programatically)
        self.bckgndBT.setIcon(Qt.QIcon(":color-fill.svg"))

        # connections.
        self.curvesLW.itemSelectionChanged.connect(self._onSelectedCurveChanged)
        self.curvesLW.itemChanged.connect(self._onItemChanged)
        self.applyBT.clicked.connect(self.onApply)
        self.resetBT.clicked.connect(self.onReset)
        self.sStyleCB.currentIndexChanged.connect(self._onSymbolStyleChanged)

        self.sStyleCB.currentIndexChanged.connect(self._onControlChanged)
        self.lStyleCB.currentIndexChanged.connect(self._onControlChanged)
        self.sColorCB.currentIndexChanged.connect(self._onControlChanged)
        self.lColorCB.currentIndexChanged.connect(self._onControlChanged)
        self.cStyleCB.currentIndexChanged.connect(self._onControlChanged)
        self.sSizeSB.valueChanged.connect(self._onControlChanged)
        self.lWidthSB.valueChanged.connect(self._onControlChanged)
        self.cAreaDSB.valueChanged.connect(self._onControlChanged)
        self.sFillCB.stateChanged.connect(self._onControlChanged)
        self.cFillCB.stateChanged.connect(self._onControlChanged)

        self.assignToY1BT.toggled[bool].connect(self.__onY1Toggled)
        self.assignToY2BT.toggled[bool].connect(self.__onY2Toggled)

        # self.bckgndBT.clicked.connect(self.changeBackgroundColor)

        # Disabled buttons until future implementations
        # (set background color and set curve labels)
        self.changeTitlesBT.setEnabled(False)
        self.bckgndBT.setEnabled(False)

        # disable the group box with the options for swap curves between Y axes
        if Y2Axis is None:
            self.groupBox.setEnabled(False)

        # set properties from curves for first launch of config dialog and
        # keeps a curvePropAdapter object
        self._onSelectedCurveChanged()
        self.curvePropAdapter = curvePropAdapter
        self.axis = None
    def __init__(self, **kwargs):
        kwargs['manager'] = kwargs.pop('pool')
        kwargs['elem_type'] = ElementType.ControllerClass
        SardanaClass.__init__(self, **kwargs)

        self.types = []
        self.dict_extra = {}
        self.api_version = 1
        klass = self.klass
        # Generic controller information
        self.ctrl_features = tuple(klass.ctrl_features)

        self.ctrl_properties = props = CaselessDict()
        self.ctrl_properties_descriptions = []
        dep_msg = ("Defining the controller property description using a " +
                   "string is deprecated, use " +
                   "sardana.pool.controller.Description constant instead.")
        for k, v in klass.class_prop.items():  # old member
            props[k] = DataInfo.toDataInfo(k, v)
            try:
                self.ctrl_properties_descriptions.append(v[Description])
            except KeyError:
                self.warning(dep_msg)
                self.ctrl_properties_descriptions.append(v['Description'])

        for k, v in klass.ctrl_properties.items():
            props[k] = DataInfo.toDataInfo(k, v)
            try:
                self.ctrl_properties_descriptions.append(v[Description])
            except KeyError:
                self.warning(dep_msg)
                self.ctrl_properties_descriptions.append(v['Description'])

        self.dict_extra['properties'] = tuple(klass.ctrl_properties)
        self.dict_extra['properties_desc'] = self.ctrl_properties_descriptions

        self.ctrl_attributes = ctrl_attrs = CaselessDict()
        for k, v in klass.ctrl_attributes.items():
            ctrl_attrs[k] = DataInfo.toDataInfo(k, v)

        self.axis_attributes = axis_attrs = CaselessDict()
        for k, v in klass.ctrl_extra_attributes.items():  # old member
            axis_attrs[k] = DataInfo.toDataInfo(k, v)
        for k, v in klass.axis_attributes.items():
            axis_attrs[k] = DataInfo.toDataInfo(k, v)

        self.types = types = self.__build_types()
        self.type_names = map(ElementType.whatis, types)

        if ElementType.PseudoMotor in types:
            self.motor_roles = tuple(klass.motor_roles)
            self.pseudo_motor_roles = tuple(klass.pseudo_motor_roles)
            if len(self.pseudo_motor_roles) == 0:
                self.pseudo_motor_roles = (klass.__name__, )
            self.dict_extra['motor_roles'] = self.motor_roles
            self.dict_extra['pseudo_motor_roles'] = self.pseudo_motor_roles

        if ElementType.PseudoCounter in types:
            self.counter_roles = tuple(klass.counter_roles)
            self.pseudo_counter_roles = tuple(klass.pseudo_counter_roles)
            if len(self.pseudo_counter_roles) == 0:
                self.pseudo_counter_roles = (klass.__name__, )
            self.dict_extra['counter_roles'] = self.counter_roles
            self.dict_extra['pseudo_counter_roles'] = self.pseudo_counter_roles

        if ElementType.IORegister in types:
            self.dict_extra['predefined_values'] = klass.predefined_values

        init_args = inspect.getargspec(klass.__init__)
        if init_args.varargs is None or init_args.keywords is None:
            self.api_version = 0
Exemple #27
0
class BaseSardanaElementContainer:

    def __init__(self):
        # dict<str, dict> where key is the type and value is:
        #     dict<str, MacroServerElement> where key is the element full name
        #                                   and value is the Element object
        self._type_elems_dict = CaselessDict()

        # dict<str, container> where key is the interface and value is the set
        # of elements which implement that interface
        self._interfaces_dict = {}

    def addElement(self, elem):
        elem_type = elem.getType()
        elem_full_name = elem.full_name

        # update type_elems
        type_elems = self._type_elems_dict.get(elem_type)
        if type_elems is None:
            self._type_elems_dict[elem_type] = type_elems = CaselessDict()
        type_elems[elem_full_name] = elem

        # update interfaces
        for interface in elem.interfaces:
            interface_elems = self._interfaces_dict.get(interface)
            if interface_elems is None:
                self._interfaces_dict[
                    interface] = interface_elems = CaselessDict()
            interface_elems[elem_full_name] = elem

    def removeElement(self, e):
        elem_type = e.getType()

        # update type_elems
        type_elems = self._type_elems_dict.get(elem_type)
        if type_elems:
            del type_elems[e.full_name]

        # update interfaces
        for interface in e.interfaces:
            interface_elems = self._interfaces_dict.get(interface)
            del interface_elems[e.full_name]

    def removeElementsOfType(self, t):
        for elem in self.getElementsOfType(t):
            self.removeElement(elem)

    def getElementsOfType(self, t):
        elems = self._type_elems_dict.get(t, {})
        return elems

    def getElementNamesOfType(self, t):
        return [e.name for e in list(self.getElementsOfType(t).values())]

    def getElementsWithInterface(self, interface):
        elems = self._interfaces_dict.get(interface, {})
        return elems

    def getElementsWithInterfaces(self, interfaces):
        ret = CaselessDict()
        for interface in interfaces:
            ret.update(self.getElementsWithInterface(interface))
        return ret

    def getElementNamesWithInterface(self, interface):
        return [e.name for e in
                list(self.getElementsWithInterface(interface).values())]

    def hasElementName(self, elem_name):
        return self.getElement(elem_name) is not None

    def getElement(self, elem_name):
        elem_name = elem_name.lower()
        for elems in list(self._type_elems_dict.values()):
            elem = elems.get(elem_name)  # full_name?
            if elem is not None:
                return elem
            for elem in list(elems.values()):
                if elem.name.lower() == elem_name:
                    return elem

    def getElementWithInterface(self, elem_name, interface):
        elem_name = elem_name.lower()
        elems = self._interfaces_dict.get(interface, {})
        if elem_name in elems:
            return elems[elem_name]
        for elem in list(elems.values()):
            if elem.name.lower() == elem_name:
                return elem

    def getElements(self):
        ret = set()
        for elems in list(self._type_elems_dict.values()):
            ret.update(list(elems.values()))
        return ret

    def getInterfaces(self):
        return self._interfaces_dict

    def getTypes(self):
        return self._type_elems_dict
Exemple #28
0
class ReadTangoAttributes(object):
    """ Generic class that has as many devices as the user wants.
    Each device has a tango attribute and a formula and the 'hardware' tango calls
    are optimized in the sense that only one call per tango device is issued.
    """
    axis_attributes = {
        TangoAttribute: {Type: str, Access: DataAccess.ReadWrite,
                         Description: 'Attribute to read (e.g. a/b/c/attr)'},
        Formula: {Type: str, Access: DataAccess.ReadWrite,
                  DefaultValue: "VALUE",
                  Description: 'The Formula to get the desired value.\n'
                  'e.g. "math.sqrt(VALUE)"'},
    }

    def __init__(self):
        #: dict<int(axis), str(reason for being in pending)>
        self._pending = {}

        #: dict<str(dev name), tuple<DeviceProxy, list<str(attributes name)>>>
        self._devices = CaselessDict()

        #: dict<int(axis), seq<str<tango full attribute name>, str<attr name>, DeviceProxy>>
        self._axis_tango_attributes = {}

        #: dict<int(axis), str<formula>>
        self._axis_formulas = {}

    def add_device(self, axis):
        self._pending[
            axis] = "No tango attribute associated to this device yet"
        self._axis_formulas[axis] = self.axis_attribute[Formula][DefaultValue]

    def delete_device(self, axis):
        if axis in self._pending:
            del self._pending[axis]
        else:
            del self._axis_tango_attributes[axis]
            del self._axis_formulas[axis]

    def state_one(self, axis):
        pending_info = self._pending.get(axis)
        if pending_info is not None:
            return State.Fault, pending_info
        return State.On, 'Always ON, just reading tango attribute'

    def pre_read_all(self):
        self._devices_read = {}

    def pre_read_one(self, axis):
        attr_name, dev = self._axis_tango_attributes[axis][1:]
        dev_attrs = self._devices_read.get(dev)
        if dev_attrs is None:
            self._
            self._devices_read[dev] = dev_attrs = []
        dev_attrs.append(attr_name)

    def read_all(self):
        pass

    def read_one(self, axis):
        pass

    def get_extra_attribute_par(self, axis, name):
        if name == TangoAttribute:
            return self._axis_tango_attributes[axis][0]
        elif name == Formula:
            return self._axis_formulas[axis]

    def set_extra_attribute_par(self, axis, name, value):
        if name == TangoAttribute:
            value = value.lower()
            self._axis_tango_attributes[axis] = data = value, None, None
            try:
                dev_name, attr_name = value.rsplit("/", 1)
                data[1] = attr_name
            except:
                self._pending[axis] = "invalid device name " + value
                raise Exception(self._pending[axis])
            dev_info = self._devices.get(dev_name)
            if dev_info is None:
                try:
                    proxy = PyTango.DeviceProxy(dev_name)
                except PyTango.DevFailed, df:
                    if len(df):
                        self._pending[axis] = df[0].reason + ": " + df[0].desc
                    else:
                        self._pending[
                            axis] = "Unknwon PyTango Error: " + str(df)
                    raise
                self._devices[dev_name] = dev_info = proxy, []
            data[2] = dev_info[0]
            dev_info[1].append(attr_name)

        elif name == Formula:
            self._axis_formulas[axis] = value
class SardanaContainer(object):
    """A container class for sardana elements"""

    def __init__(self):

        # map of all elements
        # key - element ID
        # value - pointer to the element object
        self._element_ids = {}

        # map of all elements by name
        # key - element name
        # value - pointer to the element object
        self._element_names = CaselessDict()

        # map of all elements by name
        # key - element full name
        # value - pointer to the element object
        self._element_full_names = CaselessDict()

        # map of all elements by type
        # key - element type
        # value - map where:
        #    key - element ID
        #    value - pointer to the element object
        self._element_types = {}

    def add_element(self, e):
        """Adds a new :class:`pool.PoolObject` to this container

           :param e: the pool element to be added
           :type e: :class:`pool.PoolObject`
        """
        name, full_name, id = e.get_name(), e.get_full_name(), e.get_id()
        elem_type = e.get_type()
        self._element_ids[id] = e
        self._element_names[name] = e
        self._element_full_names[full_name] = e
        type_elems = self._element_types.get(elem_type)
        if type_elems is None:
            self._element_types[elem_type] = type_elems = {}
        type_elems[id] = e
        return e

    def remove_element(self, e):
        """Removes the :class:`pool.PoolObject` from this container

           :param e: the pool object to be removed
           :type e: :class:`pool.PoolObject`

           :throw: KeyError
        """
        name, full_name, id = e.get_name(), e.get_full_name(), e.get_id()
        elem_type = e.get_type()
        del self._element_ids[id]
        del self._element_names[name]
        del self._element_full_names[full_name]
        type_elems = self._element_types.get(elem_type)
        del type_elems[id]

    def get_element_id_map(self):
        """Returns a reference to the internal pool object ID map

           :return: the internal pool object ID map
           :rtype: dict<id, pool.PoolObject>
        """
        return self._element_ids

    def get_element_name_map(self):
        """Returns a reference to the internal pool object name map

           :return: the internal pool object name map
           :rtype: dict<str, pool.PoolObject>
        """
        return self._element_names

    def get_element_type_map(self):
        """Returns a reference to the internal pool object type map

           :return: the internal pool object type map
           :rtype: dict<pool.ElementType, dict<id, pool.PoolObject>>
        """
        return self._element_types

    def get_element(self, **kwargs):
        """Returns a reference to the requested pool object

           :param kwargs: if key 'id' given: search by ID
                          else if key 'full_name' given: search by full name
                          else if key 'name' given: search by name

           :return: the pool object
           :rtype: pool.PoolObject

           :throw: KeyError
        """
        if kwargs.has_key("id"):
            id = kwargs.pop("id")
            return self.get_element_by_id(id, **kwargs)

        if kwargs.has_key("full_name"):
            full_name = kwargs.pop("full_name")
            return self.get_element_by_full_name(full_name, **kwargs)

        name = kwargs.pop("name")
        return self.get_element_by_name(name, **kwargs)

    def get_element_by_name(self, name, **kwargs):
        """Returns a reference to the requested pool object

           :param name: pool object name
           :type name: :obj:`str`

           :return: the pool object
           :rtype: pool.PoolObject

           :throw: KeyError
        """
        ret = self._element_names.get(name)
        if ret is None:
            raise KeyError("There is no element with name '%s'" % name)
        return ret

    def get_element_by_full_name(self, full_name, **kwargs):
        """Returns a reference to the requested pool object

           :param name: pool object full name
           :type name: :obj:`str`

           :return: the pool object
           :rtype: pool.PoolObject

           :throw: KeyError
        """
        ret = self._element_full_names.get(full_name)
        if ret is None:
            raise KeyError(
                "There is no element with full name '%s'" % full_name)
        return ret

    def get_element_by_id(self, id, **kwargs):
        """Returns a reference to the requested pool object

           :param id: pool object ID
           :type id: int

           :return: the pool object
           :rtype: pool.PoolObject

           :throw: KeyError
        """
        ret = self._element_ids.get(id)
        if ret is None:
            raise KeyError("There is no element with ID '%d'" % id)
        return ret

    def get_elements_by_type(self, t):
        """Returns a list of all pool objects of the given type

           :param t: element type
           :type t: pool.ElementType

           :return: list of pool objects
           :rtype: seq<pool.PoolObject>
        """
        elem_types_dict = self._element_types.get(t)
        if elem_types_dict is None:
            return []
        return elem_types_dict.values()

    def get_element_names_by_type(self, t):
        """Returns a list of all pool object names of the given type

           :param t: element type
           :type t: pool.ElementType

           :return: list of pool object names
           :rtype: seq<str>
        """
        return [elem.get_name() for elem in self.get_elements_by_type(t)]

    def rename_element(self, old_name, new_name):
        """Rename an object

           :param old_name: old object name
           :type old_name: :obj:`str`
           :param new_name: new object name
           :type new_name: :obj:`str`
        """
        element = self._element_names.pop(old_name, None)
        if element is None:
            raise KeyError('There is no element with name %s' % old_name)
        element.name = new_name
        self._element_names[new_name] = element

    def check_element(self, name, full_name):
        raise_element_name = True
        try:
            elem = self.get_element(name=name)
        except:
            raise_element_name = False
        if raise_element_name:
            elem_type = ElementType[elem.get_type()]
            raise Exception("A %s with name '%s' already exists"
                            % (elem_type, name))

        raise_element_full_name = True
        try:
            elem = self.get_element(full_name=full_name)
        except:
            raise_element_full_name = False
        if raise_element_full_name:
            elem_type = ElementType[elem.get_type()]
            raise Exception("A %s with full name '%s' already exists"
                            % (elem_type, full_name))
Exemple #30
0
class SardanaContainer(object):
    """A container class for sardana elements"""
    def __init__(self):

        # map of all elements
        # key - element ID
        # value - pointer to the element object
        self._element_ids = {}

        # map of all elements by name
        # key - element name
        # value - pointer to the element object
        self._element_names = CaselessDict()

        # map of all elements by name
        # key - element full name
        # value - pointer to the element object
        self._element_full_names = CaselessDict()

        # map of all elements by type
        # key - element type
        # value - map where:
        #    key - element ID
        #    value - pointer to the element object
        self._element_types = {}

    def add_element(self, e):
        """Adds a new :class:`pool.PoolObject` to this container
           
           :param e: the pool element to be added
           :type e: :class:`pool.PoolObject`
        """
        name, full_name, id = e.get_name(), e.get_full_name(), e.get_id()
        elem_type = e.get_type()
        self._element_ids[id] = e
        self._element_names[name] = e
        self._element_full_names[full_name] = e
        type_elems = self._element_types.get(elem_type)
        if type_elems is None:
            self._element_types[elem_type] = type_elems = {}
        type_elems[id] = e
        return e

    def remove_element(self, e):
        """Removes the :class:`pool.PoolObject` from this container
           
           :param e: the pool object to be removed
           :type e: :class:`pool.PoolObject`
           
           :throw: KeyError
        """
        name, full_name, id = e.get_name(), e.get_full_name(), e.get_id()
        elem_type = e.get_type()
        del self._element_ids[id]
        del self._element_names[name]
        del self._element_full_names[full_name]
        type_elems = self._element_types.get(elem_type)
        del type_elems[id]

    def get_element_id_map(self):
        """Returns a reference to the internal pool object ID map
           
           :return: the internal pool object ID map
           :rtype: dict<id, pool.PoolObject>
        """
        return self._element_ids

    def get_element_name_map(self):
        """Returns a reference to the internal pool object name map
           
           :return: the internal pool object name map
           :rtype: dict<str, pool.PoolObject>
        """
        return self._element_names

    def get_element_type_map(self):
        """Returns a reference to the internal pool object type map
           
           :return: the internal pool object type map
           :rtype: dict<pool.ElementType, dict<id, pool.PoolObject>>
        """
        return self._element_types

    def get_element(self, **kwargs):
        """Returns a reference to the requested pool object
           
           :param kwargs: if key 'id' given: search by ID
                          else if key 'full_name' given: search by full name
                          else if key 'name' given: search by name
           
           :return: the pool object 
           :rtype: pool.PoolObject
           
           :throw: KeyError
        """
        if kwargs.has_key("id"):
            id = kwargs.pop("id")
            return self.get_element_by_id(id, **kwargs)

        if kwargs.has_key("full_name"):
            full_name = kwargs.pop("full_name")
            return self.get_element_by_full_name(full_name, **kwargs)

        name = kwargs.pop("name")
        return self.get_element_by_name(name, **kwargs)

    def get_element_by_name(self, name, **kwargs):
        """Returns a reference to the requested pool object
           
           :param name: pool object name
           :type name: str
           
           :return: the pool object 
           :rtype: pool.PoolObject
           
           :throw: KeyError
        """
        ret = self._element_names.get(name)
        if ret is None:
            raise KeyError("There is no element with name '%s'" % name)
        return ret

    def get_element_by_full_name(self, full_name, **kwargs):
        """Returns a reference to the requested pool object
           
           :param name: pool object full name
           :type name: str
           
           :return: the pool object 
           :rtype: pool.PoolObject
           
           :throw: KeyError
        """
        ret = self._element_full_names.get(full_name)
        if ret is None:
            raise KeyError("There is no element with full name '%s'" %
                           full_name)
        return ret

    def get_element_by_id(self, id, **kwargs):
        """Returns a reference to the requested pool object
           
           :param id: pool object ID
           :type id: int
           
           :return: the pool object 
           :rtype: pool.PoolObject
           
           :throw: KeyError
        """
        ret = self._element_ids.get(id)
        if ret is None:
            raise KeyError("There is no element with ID '%d'" % id)
        return ret

    def get_elements_by_type(self, t):
        """Returns a list of all pool objects of the given type
           
           :param t: element type
           :type t: pool.ElementType
           
           :return: list of pool objects
           :rtype: seq<pool.PoolObject>
        """
        elem_types_dict = self._element_types.get(t)
        if elem_types_dict is None:
            return []
        return elem_types_dict.values()

    def get_element_names_by_type(self, t):
        """Returns a list of all pool object names of the given type
           
           :param t: element type
           :type t: pool.ElementType
           
           :return: list of pool object names
           :rtype: seq<str>
        """
        return [elem.get_name() for elem in self.get_elements_by_type(t)]

    def rename_element(self, old_name, new_name):
        """Rename an object
           
           :param old_name: old object name
           :type old_name: str
           :param new_name: new object name
           :type new_name: str
        """
        element = self._element_names.pop(old_name, None)
        if element is None:
            raise KeyError('There is no element with name %s' % old_name)
        element.name = new_name
        self._element_names[new_name] = element

    def check_element(self, name, full_name):
        raise_element_name = True
        try:
            elem = self.get_element(name=name)
        except:
            raise_element_name = False
        if raise_element_name:
            elem_type = ElementType[elem.get_type()]
            raise Exception("A %s with name '%s' already exists" %
                            (elem_type, name))

        raise_element_full_name = True
        try:
            elem = self.get_element(full_name=full_name)
        except:
            raise_element_full_name = False
        if raise_element_full_name:
            elem_type = ElementType[elem.get_type()]
            raise Exception("A %s with full name '%s' already exists" %
                            (elem_type, full_name))
Exemple #31
0
class Pool(PoolContainer, PoolObject, SardanaElementManager, SardanaIDManager):
    """The central pool class."""

    #: Default value representing the number of state reads per position
    #: read during a motion loop
    Default_MotionLoop_StatesPerPosition = 10

    #: Default value representing the sleep time for each motion loop
    Default_MotionLoop_SleepTime = 0.01

    #: Default value representing the number of state reads per value
    #: read during a motion loop
    Default_AcqLoop_StatesPerValue = 10

    #: Default value representing the sleep time for each acquisition loop
    Default_AcqLoop_SleepTime = 0.01

    Default_DriftCorrection = True

    def __init__(self, full_name, name=None):
        self._path_id = None
        self._motion_loop_states_per_position = self.Default_MotionLoop_StatesPerPosition
        self._motion_loop_sleep_time = self.Default_MotionLoop_SleepTime
        self._acq_loop_states_per_value = self.Default_AcqLoop_StatesPerValue
        self._acq_loop_sleep_time = self.Default_AcqLoop_SleepTime
        self._drift_correction = self.Default_DriftCorrection
        self._remote_log_handler = None

        # dict<str, dict<str, str>>
        # keys are acquisition channel names and value is a dict describing the
        # channel containing:
        #  - 'name': with value being the channel name (given by user)
        #  - 'full_name': acq channel full name (ex: tango attribute)
        #  - 'origin': 'local' if local to this server or 'remote' if a remote
        #    channel
        self._extra_acquisition_element_names = CaselessDict()

        PoolContainer.__init__(self)
        PoolObject.__init__(self,
                            full_name=full_name,
                            name=name,
                            id=InvalidId,
                            pool=self,
                            elem_type=ElementType.Pool)
        self._monitor = PoolMonitor(self, "PMonitor", auto_start=False)
        # self.init_local_logging()
        ControllerManager().set_pool(self)

    # TODO: not ready to use. path must be the same as the one calculated in
    # sardana.tango.core.util:prepare_logging
    def init_local_logging(self):
        log = logging.getLogger("Controller")
        log.propagate = 0
        path = os.path.join(os.sep, "tmp", "tango")
        log_file_name = os.path.join(path, 'controller.log.txt')
        try:
            if not os.path.exists(path):
                os.makedirs(path, 0777)
            f_h = logging.handlers.RotatingFileHandler(log_file_name,
                                                       maxBytes=1E7,
                                                       backupCount=5)

            f_h.setFormatter(self.getLogFormat())
            log.addHandler(f_h)
            self.info("Controller logs stored in %s", log_file_name)
        except:
            self.warning("Controller logs could not be created!")
            self.debug("Details:", exc_info=1)

    def clear_remote_logging(self):
        rh = self._remote_log_handler
        if rh is None:
            return
        log = logging.getLogger("Controller")
        log.removeHandler(rh)
        self._remote_log_handler = None

    def init_remote_logging(self, host=None, port=None):
        """Initializes remote logging.

        :param host: host name [default: None, meaning use the machine host name
                     as returned by :func:`socket.gethostname`].
        :type host: str
        :param port: port number [default: None, meaning use
                     :data:`logging.handlers.DEFAULT_TCP_LOGGING_PORT`"""
        log = logging.getLogger("Controller")

        # port 0 means no remote logging
        if port == 0:
            return

        # first check that the handler has not been initialized yet
        for handler in log.handlers:
            if isinstance(handler, logging.handlers.SocketHandler):
                return
        if host is None:
            import socket
            host = socket.gethostname()
            #host = socket.getfqdn()
        if port is None:
            port = logging.handlers.DEFAULT_TCP_LOGGING_PORT
        handler = logging.handlers.SocketHandler(host, port)
        if hasattr(handler, 'retryMax'):
            # default max retry is 30s which seems too much. Let's make it that
            # the pool tries to reconnect to a client every 10s (similar to the
            # tango event reconnection
            handler.retryMax = 10.0
        log.addHandler(handler)
        self.info("Remote logging initialized for host '%s' on port %d", host,
                  port)

    def serialize(self, *args, **kwargs):
        kwargs = PoolObject.serialize(self, *args, **kwargs)
        kwargs['type'] = self.__class__.__name__
        kwargs['id'] = InvalidId
        kwargs['parent'] = None
        return kwargs

    def set_motion_loop_sleep_time(self, motion_loop_sleep_time):
        self._motion_loop_sleep_time = motion_loop_sleep_time

    def get_motion_loop_sleep_time(self):
        return self._motion_loop_sleep_time

    motion_loop_sleep_time = property(get_motion_loop_sleep_time,
                                      set_motion_loop_sleep_time,
                                      doc="motion sleep time (s)")

    def set_motion_loop_states_per_position(self,
                                            motion_loop_states_per_position):
        self._motion_loop_states_per_position = motion_loop_states_per_position

    def get_motion_loop_states_per_position(self):
        return self._motion_loop_states_per_position

    motion_loop_states_per_position = property(
        get_motion_loop_states_per_position,
        set_motion_loop_states_per_position,
        doc="Number of State reads done before doing a position read in the "
        "motion loop")

    def set_acq_loop_sleep_time(self, acq_loop_sleep_time):
        self._acq_loop_sleep_time = acq_loop_sleep_time

    def get_acq_loop_sleep_time(self):
        return self._acq_loop_sleep_time

    acq_loop_sleep_time = property(get_acq_loop_sleep_time,
                                   set_acq_loop_sleep_time,
                                   doc="acquisition sleep time (s)")

    def set_acq_loop_states_per_value(self, acq_loop_states_per_value):
        self._acq_loop_states_per_value = acq_loop_states_per_value

    def get_acq_loop_states_per_value(self):
        return self._acq_loop_states_per_value

    acq_loop_states_per_value = property(
        get_acq_loop_states_per_value,
        set_acq_loop_states_per_value,
        doc="Number of State reads done before doing a value read in the "
        "acquisition loop")

    def set_drift_correction(self, drift_correction):
        self._drift_correction = drift_correction

    def get_drift_correction(self):
        return self._drift_correction

    drift_correction = property(get_drift_correction,
                                set_drift_correction,
                                doc="drift correction")

    @property
    def monitor(self):
        return self._monitor

    @property
    def ctrl_manager(self):
        return ControllerManager()

    def set_python_path(self, path):
        mod_man = ModuleManager()
        if self._path_id is not None:
            mod_man.remove_python_path(self._path_id)
        self._path_id = mod_man.add_python_path(path)

    def set_path(self, path):
        self.ctrl_manager.setControllerPath(path, reload=False)

    def get_controller_libs(self):
        return self.ctrl_manager.getControllerLibs()

    def get_controller_lib_names(self):
        return self.ctrl_manager.getControllerLibNames()

    def get_controller_class_names(self):
        return self.ctrl_manager.getControllerNames()

    def get_controller_classes(self):
        return self.ctrl_manager.getControllers()

    def get_controller_class_info(self, name):
        return self.ctrl_manager.getControllerMetaClass(name)

    def get_controller_classes_info(self, names):
        return self.ctrl_manager.getControllerMetaClasses(names)

    def get_controller_libs_summary_info(self):
        libs = self.get_controller_libs()
        ret = []
        for ctrl_lib_info in libs:
            elem = "%s (%s)" % (ctrl_lib_info.getName(),
                                ctrl_lib_info.getFileName())
            ret.append(elem)
        return ret

    def get_controller_classes_summary_info(self):
        ctrl_classes = self.get_controller_classes()
        ret = []
        for ctrl_class_info in ctrl_classes:
            types = ctrl_class_info.getTypes()
            types_str = [
                TYPE_MAP_OBJ[t].name for t in types
                if t != ElementType.Controller
            ]
            types_str = ", ".join(types_str)
            elem = "%s (%s) %s" % (ctrl_class_info.getName(),
                                   ctrl_class_info.getFileName(), types_str)
            ret.append(elem)
        return ret

    def get_elements_str_info(self, obj_type=None):
        if obj_type is None:
            objs = self.get_element_id_map().values()
            objs.extend(self.get_controller_classes())
            objs.extend(self.get_controller_libs())
        elif obj_type == ElementType.ControllerClass:
            objs = self.get_controller_classes()
        elif obj_type == ElementType.ControllerLibrary:
            objs = self.get_controller_libs()
        else:
            objs = self.get_elements_by_type(obj_type)
        name = self.full_name
        return [obj.str(pool=name) for obj in objs]

    def get_elements_info(self, obj_type=None):
        if obj_type is None:
            objs = self.get_element_id_map().values()
            objs.extend(self.get_controller_classes())
            objs.extend(self.get_controller_libs())
            objs.append(self)
        elif obj_type == ElementType.ControllerClass:
            objs = self.get_controller_classes()
        elif obj_type == ElementType.ControllerLibrary:
            objs = self.get_controller_libs()
        else:
            objs = self.get_elements_by_type(obj_type)
        name = self.full_name
        return [obj.serialize(pool=name) for obj in objs]

    def get_acquisition_elements_info(self):
        ret = []
        for _, element in self.get_element_name_map().items():
            if element.get_type() not in TYPE_ACQUIRABLE_ELEMENTS:
                continue
            acq_channel = element.get_default_acquisition_channel()
            full_name = "{0}/{1}".format(element.full_name, acq_channel)
            info = dict(name=element.name, full_name=full_name, origin='local')
            ret.append(info)
        ret.extend(self._extra_acquisition_element_names.values())
        return ret

    def get_acquisition_elements_str_info(self):
        return map(self.str_object, self.get_acquisition_elements_info())

    def create_controller(self, **kwargs):
        ctrl_type = kwargs['type']
        lib = kwargs['library']
        class_name = kwargs['klass']
        name = kwargs['name']
        elem_type = ElementType[ctrl_type]
        mod_name, _ = os.path.splitext(lib)
        kwargs['module'] = mod_name

        td = TYPE_MAP_OBJ[ElementType.Controller]
        klass_map = td.klass
        auto_full_name = td.auto_full_name
        kwargs['full_name'] = full_name = \
            kwargs.get("full_name", auto_full_name.format(**kwargs))
        self.check_element(name, full_name)

        ctrl_class_info = None
        ctrl_lib_info = self.ctrl_manager.getControllerLib(mod_name)
        if ctrl_lib_info is not None:
            ctrl_class_info = ctrl_lib_info.get_controller(class_name)

        kwargs['pool'] = self
        kwargs['class_info'] = ctrl_class_info
        kwargs['lib_info'] = ctrl_lib_info
        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        # For pseudo controllers make sure 'role_ids' is given
        klass = klass_map.get(elem_type, PoolController)
        if elem_type in TYPE_PSEUDO_ELEMENTS:
            motor_roles = kwargs['role_ids']

        # make sure the properties (that may have come from a case insensitive
        # environment like tango) are made case sensitive
        props = {}
        if ctrl_class_info is None:
            ctrl_prop_info = {}
        else:
            ctrl_prop_info = ctrl_class_info.ctrl_properties
        for k, v in kwargs['properties'].items():
            info = ctrl_prop_info.get(k)
            if info is None:
                props[k] = v
            else:
                props[info.name] = v
        kwargs['properties'] = props

        ctrl = klass(**kwargs)
        ret = self.add_element(ctrl)
        self.fire_event(EventType("ElementCreated"), ctrl)
        return ret

    def create_element(self, **kwargs):
        etype = kwargs['type']
        ctrl_id = kwargs['ctrl_id']
        axis = kwargs['axis']
        elem_type = ElementType[etype]
        name = kwargs['name']

        try:
            ctrl = self.get_element(id=ctrl_id)
        except:
            raise Exception("No controller with id '%d' found" % ctrl_id)

        elem_axis = ctrl.get_element(axis=axis)
        if elem_axis is not None:
            raise Exception("Controller already contains axis %d (%s)" %
                            (axis, elem_axis.get_name()))

        kwargs['pool'] = self
        kwargs['ctrl'] = ctrl
        kwargs['ctrl_name'] = ctrl.get_name()

        td = TYPE_MAP_OBJ[elem_type]
        klass = td.klass
        auto_full_name = td.auto_full_name
        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))

        self.check_element(name, full_name)

        if ctrl.is_online():
            ctrl_types, ctrl_id = ctrl.get_ctrl_types(), ctrl.get_id()
            if elem_type not in ctrl_types:
                ctrl_type_str = ElementType.whatis(ctrl_types[0])
                raise Exception("Cannot create %s in %s controller" %
                                (etype, ctrl_type_str))

        # check if controller is online
        # check if axis is allowed
        # create the element in the controller

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)
        elem = klass(**kwargs)
        ctrl.add_element(elem)
        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def create_motor_group(self, **kwargs):
        name = kwargs['name']
        elem_ids = kwargs["user_elements"]

        kwargs['pool'] = self
        kwargs["pool_name"] = self.name
        td = TYPE_MAP_OBJ[ElementType.MotorGroup]
        klass = td.klass
        auto_full_name = td.auto_full_name
        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))
        kwargs.pop('pool_name')

        self.check_element(name, full_name)

        for elem_id in elem_ids:
            elem = self.pool.get_element(id=elem_id)
            if elem.get_type() not in (ElementType.Motor,
                                       ElementType.PseudoMotor):
                raise Exception("%s is not a motor" % elem.name)

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        elem = klass(**kwargs)

        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def create_measurement_group(self, **kwargs):
        name = kwargs['name']
        elem_ids = kwargs["user_elements"]

        kwargs['pool'] = self
        kwargs["pool_name"] = self.name

        td = TYPE_MAP_OBJ[ElementType.MeasurementGroup]
        klass = td.klass
        auto_full_name = td.auto_full_name

        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))
        kwargs.pop('pool_name')

        self.check_element(name, full_name)

        for elem_id in elem_ids:
            if isinstance(elem_id, int):
                self.pool.get_element(id=elem_id)
            else:
                tg_attr_validator = TangoAttributeNameValidator()
                params = tg_attr_validator.getParams(elem_id)
                if params is None:
                    raise Exception("Invalid channel name %s" % elem_id)

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        elem = klass(**kwargs)

        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def rename_element(self, old_name, new_name):
        elem = self.get_element_by_name(old_name)
        elem.controller.rename_element(old_name, new_name)
        PoolContainer.rename_element(self, old_name, new_name)
        elem = self.get_element_by_name(new_name)
        self.fire_event(EventType("ElementChanged"), elem)

    def delete_element(self, name):
        try:
            elem = self.get_element(name=name)
        except:
            try:
                elem = self.get_element(full_name=name)
            except:
                raise Exception("There is no element with name '%s'" % name)

        elem_type = elem.get_type()
        if elem_type == ElementType.Controller:
            if len(elem.get_elements()) > 0:
                raise Exception("Cannot delete controller with elements. "
                                "Delete elements first")
        elif elem_type == ElementType.Instrument:
            if elem.has_instruments():
                raise Exception("Cannot delete instrument with instruments. "
                                "Delete instruments first")
            if elem.has_elements():
                raise Exception("Cannot delete instrument with elements")
            parent_instrument = elem.parent_instrument
            if parent_instrument is not None:
                parent_instrument.remove_instrument(elem)
        elif hasattr(elem, "get_controller"):
            ctrl = elem.get_controller()
            ctrl.remove_element(elem)
            instrument = elem.instrument
            if instrument is not None:
                instrument.remove_element(elem)

        self.remove_element(elem)

        self.fire_event(EventType("ElementDeleted"), elem)

    def create_instrument(self, full_name, klass_name, id=None):
        is_root = full_name.count('/') == 1

        if is_root:
            parent_full_name, _ = '', full_name[1:]
            parent = None
        else:
            parent_full_name, _ = full_name.rsplit('/', 1)
            try:
                parent = self.get_element_by_full_name(parent_full_name)
            except:
                raise Exception("No parent instrument named '%s' found" %
                                parent_full_name)
            if parent.get_type() != ElementType.Instrument:
                raise Exception("%s is not an instrument as expected" %
                                parent_full_name)

        self.check_element(full_name, full_name)

        td = TYPE_MAP_OBJ[ElementType.Instrument]
        klass = td.klass

        if id is None:
            id = self.get_new_id()
        else:
            self.reserve_id(id)
        elem = klass(id=id,
                     name=full_name,
                     full_name=full_name,
                     parent=parent,
                     klass=klass_name,
                     pool=self)
        if parent:
            parent.add_instrument(elem)
        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def stop(self):
        msg = ""
        controllers = self.get_elements_by_type(ElementType.Controller)
        for controller in controllers:
            if controller.is_pseudo():
                continue
            elif ElementType.IORegister in controller.get_ctrl_types():
                # Skip IOR since they are not stoppable
                continue
            error_elements = controller.stop_elements()
            if len(error_elements) > 0:
                element_names = ""
                for element in error_elements:
                    element_names += element.name + " "
                msg += ("Controller %s -> %s\n" %
                        (controller.name, element_names))
                self.error("Unable to stop %s controller: "
                           "Stop of elements %s failed" %
                           (controller.name, element_names))
        if msg:
            msg_init = "Elements which could not be stopped:\n"
            raise Exception(msg_init + msg)

    def abort(self):
        msg = ""
        controllers = self.get_elements_by_type(ElementType.Controller)
        for controller in controllers:
            if controller.is_pseudo():
                continue
            elif ElementType.IORegister in controller.get_ctrl_types():
                # Skip IOR since they are not stoppable
                continue
            error_elements = controller.abort_elements()
            if len(error_elements) > 0:
                element_names = ""
                for element in error_elements:
                    element_names += element.name + " "
                msg += ("Controller %s -> %s\n" %
                        (controller.name, element_names))
                self.error("Unable to abort %s controller: "
                           "Abort of elements %s failed" %
                           (controller.name, element_names))
        if msg:
            msg_init = "Elements which could not be aborted:\n"
            raise Exception(msg_init + msg)

    # --------------------------------------------------------------------------
    # (Re)load code
    # --------------------------------------------------------------------------

    def reload_controller_lib(self, lib_name):
        manager = self.ctrl_manager

        old_lib = manager.getControllerLib(lib_name)
        new_elements, changed_elements, deleted_elements = [], [], []
        old_ctrl_classes = ()
        if old_lib is not None:
            ctrl_infos = old_lib.get_controllers()
            pool_ctrls = self.get_elements_by_type(ElementType.Controller)
            init_pool_ctrls = []
            for pool_ctrl in pool_ctrls:
                if pool_ctrl.get_ctrl_info() in ctrl_infos:
                    init_pool_ctrls.append(pool_ctrl)
            old_ctrl_classes = ctrl_infos
            changed_elements.append(old_lib)

        new_lib = manager.reloadControllerLib(lib_name)

        if old_lib is None:
            new_elements.extend(new_lib.get_controllers())
            new_elements.append(new_lib)
        else:
            new_names = set([ctrl.name for ctrl in new_lib.get_controllers()])
            old_names = set([ctrl.name for ctrl in old_lib.get_controllers()])
            changed_names = set.intersection(new_names, old_names)
            deleted_names = old_names.difference(new_names)
            new_names = new_names.difference(old_names)

            for new_name in new_names:
                new_elements.append(new_lib.get_controller(new_name))
            for changed_name in changed_names:
                changed_elements.append(new_lib.get_controller(changed_name))
            for deleted_name in deleted_names:
                deleted_elements.append(old_lib.get_controller(deleted_name))

        evt = {
            "new": new_elements,
            "change": changed_elements,
            "del": deleted_elements
        }

        self.fire_event(EventType("ElementsChanged"), evt)

        if old_lib is not None:
            for pool_ctrl in init_pool_ctrls:
                pool_ctrl.re_init()

    def reload_controller_class(self, class_name):
        ctrl_info = self.ctrl_manager.getControllerMetaClass(class_name)
        lib_name = ctrl_info.module_name
        self.reload_controller_lib(lib_name)

    def get_element_id_graph(self):
        physical_elems_id_map = {}
        elem_type_map = self.get_element_type_map()
        for elem_type in TYPE_PHYSICAL_ELEMENTS:
            physical_elems_id_map.update(elem_type_map[elem_type])
        # TODO

    def _build_element_id_dependencies(self, elem_id, graph=None):
        if graph is None:
            graph = Graph()
        elem = self.get_element_by_id(elem_id)
        if elem.get_id() in graph or elem.get_type() in TYPE_PHYSICAL_ELEMENTS:
            return graph
        graph[elem_id] = list(elem.get_user_element_ids())
        return graph

    def get_moveable_id_graph(self):
        moveable_elems_id_map = {}
        elem_type_map = self.get_element_type_map()
        for elem_type in TYPE_MOVEABLE_ELEMENTS:
            moveable_elems_id_map.update(elem_type_map[elem_type])
        graph = Graph()
        for moveable_id in moveable_elems_id_map:
            self._build_element_id_dependencies(moveable_id, graph)
        return graph

    def _build_element_dependencies(self, elem, graph=None):
        if graph is None:
            graph = Graph()
        if elem.get_id() in graph or elem.get_type() in TYPE_PHYSICAL_ELEMENTS:
            return graph
        graph[elem] = list(elem.get_user_elements())
        return graph

    def get_moveable_graph(self):
        moveable_elems_map = {}
        elem_type_map = self.get_element_type_map()
        for elem_type in TYPE_MOVEABLE_ELEMENTS:
            moveable_elems_map.update(elem_type_map[elem_type])
        graph = Graph()
        for moveable in moveable_elems_map.values():
            self._build_element_dependencies(moveable, graph)
        return graph
Exemple #32
0
 def _initEnv(self):
     self._macro_env, self._global_env = {}, {}
     self._door_env = CaselessDict()
Exemple #33
0
class BaseDoor(MacroServerDevice):
    """ Class encapsulating Door device functionality."""

    On = PyTango.DevState.ON
    Running = PyTango.DevState.RUNNING
    Paused = PyTango.DevState.STANDBY

    Critical = 'Critical'
    Error = 'Error'
    Warning = 'Warning'
    Info = 'Info'
    Output = 'Output'
    Debug = 'Debug'
    Result = 'Result'
    RecordData = 'RecordData'

    BlockStart = '<BLOCK>'
    BlockFinish = '</BLOCK>'

    log_streams = (Error, Warning, Info, Output, Debug, Result)

    # maximum execution time without user interruption
    # this also means a time window within door state events must arrive
    # 0.1 s was not enough on Windows (see sardana-ord/sardana#725)
    InteractiveTimeout = .3

    def __init__(self, name, **kw):
        self._log_attr = CaselessDict()
        self._block_lines = 0
        self._in_block = False
        self._macro_server = None
        self._running_macros = None
        self._running_macro = None
        self._last_running_macro = None
        self._user_xml = None
        self._ignore_logs = kw.get("ignore_logs", False)
        self._silent = kw.get("silent", True)
        self._debug = kw.get("debug", False)
        self._output_stream = kw.get("output", sys.stdout)
        self._writeLock = threading.Lock()
        self._input_handler = self.create_input_handler()
        self._len_last_data_line = 1

        self.call__init__(MacroServerDevice, name, **kw)

        self._old_door_state = PyTango.DevState.UNKNOWN
        self._old_sw_door_state = TaurusDevState.Undefined

        self.stateObj.addListener(self.stateChanged)

        for log_name in self.log_streams:
            tg_attr = self.getAttribute(log_name)
            attr = LogAttr(self, log_name, None, tg_attr)
            if log_name == 'Result':
                attr.subscribeEvent(self.resultReceived, log_name)
            else:
                attr.subscribeEvent(self.logReceived, log_name)
            self._log_attr[log_name] = attr

        self.__input_attr = self.getAttribute("Input")
        self.__input_attr.addListener(self.inputReceived)

        self.__record_data_attr = self.getAttribute('RecordData')
        self.__record_data_attr.addListener(self.recordDataReceived)

        self.__macro_status_attr = self.getAttribute('MacroStatus')
        self.__macro_status_attr.addListener(self.macroStatusReceived)

        self._experiment_configuration = ExperimentConfiguration(self)

    def create_input_handler(self):
        return BaseInputHandler()

    def get_input_handler(self):
        return self._input_handler

    def get_color_mode(self):
        return "NoColor"

    # def macrosChanged(self, s, v, t):
    #    pass

    @property
    def log_start(self):
        if not hasattr(self, "_log_start"):
            import taurus.core.util.console
            if self.get_color_mode() == "NoColor":
                kls = taurus.core.util.console.NoColors
            else:
                kls = taurus.core.util.console.TermColors
            self._log_start = {
                BaseDoor.Critical: kls.LightRed,
                BaseDoor.Error: kls.Red,
                BaseDoor.Info: kls.LightBlue,
                BaseDoor.Warning: kls.Brown,
                BaseDoor.Output: kls.Normal,
                BaseDoor.Debug: kls.DarkGray,
                BaseDoor.Result: kls.LightGreen
            }
        return self._log_start

    @property
    def log_stop(self):
        if not hasattr(self, "_log_stop"):
            import taurus.core.util.console
            if self.get_color_mode() == "NoColor":
                kls = taurus.core.util.console.NoColors
            else:
                kls = taurus.core.util.console.TermColors
            self._log_stop = {
                BaseDoor.Critical: kls.Normal,
                BaseDoor.Error: kls.Normal,
                BaseDoor.Info: kls.Normal,
                BaseDoor.Warning: kls.Normal,
                BaseDoor.Output: kls.Normal,
                BaseDoor.Debug: kls.Normal,
                BaseDoor.Result: kls.Normal
            }
        return self._log_stop

    def getStateAttr(self):
        return self._state_attr

    @property
    def macro_server(self):
        if self._macro_server is None:
            self._macro_server = self._get_macroserver_for_door()
        return self._macro_server

    def _get_macroserver_for_door(self):
        """Returns the MacroServer device object in the same DeviceServer as
        this door"""
        db = self.getParentObj()
        door_name = self.dev_name()
        server_list = list(db.get_server_list('MacroServer/*'))
        server_list += list(db.get_server_list('Sardana/*'))
        for server in server_list:
            server_devs = db.get_device_class_list(server)
            devs, klasses = server_devs[0::2], server_devs[1::2]
            for dev in devs:
                if dev.lower() == door_name:
                    for i, klass in enumerate(klasses):
                        if klass == 'MacroServer':
                            full_name = db.getFullName() + "/" + devs[i]
                            return self.factory().getDevice(full_name)
        else:
            return None

    def setDebugMode(self, state):
        self._debug = state

    def getDebugMode(self):
        return self._debug

    def setSilent(self, yesno):
        self._silent = yesno

    def isSilent(self):
        return self._silent

    def getLogObj(self, log_name='Debug'):
        return self._log_attr.get(log_name, None)

    def getRunningXML(self):
        return self._user_xml

    def getRunningMacro(self):
        return self._running_macro

    def getLastRunningMacro(self):
        return self._last_running_macro

    def abort(self, synch=True):
        if not synch:
            self.command_inout("AbortMacro")
            return

        evt_wait = AttributeEventWait(self.getAttribute("state"))
        evt_wait.lock()
        try:
            time_stamp = time.time()
            self.command_inout("AbortMacro")
            evt_wait.waitEvent(self.Running,
                               equal=False,
                               after=time_stamp,
                               timeout=self.InteractiveTimeout)
        finally:
            evt_wait.unlock()
            evt_wait.disconnect()

    def release(self, synch=True):
        if not synch:
            try:
                self.command_inout("ReleaseMacro")
            except PyTango.DevFailed as df:
                # Macro already finished - no need to release
                if df.args[0].reason == "API_CommandNotAllowed":
                    pass
            return

        evt_wait = AttributeEventWait(self.getAttribute("state"))
        evt_wait.lock()
        try:
            time_stamp = time.time()
            try:
                self.command_inout("ReleaseMacro")
            except PyTango.DevFailed as df:
                # Macro already finished - no need to release
                if df.args[0].reason == "API_CommandNotAllowed":
                    return
            evt_wait.waitEvent(self.Running,
                               equal=False,
                               after=time_stamp,
                               timeout=self.InteractiveTimeout)
        finally:
            evt_wait.unlock()
            evt_wait.disconnect()

    def stop(self, synch=True):
        if not synch:
            self.command_inout("StopMacro")
            return

        evt_wait = AttributeEventWait(self.getAttribute("state"))
        evt_wait.lock()
        try:
            time_stamp = time.time()
            self.command_inout("StopMacro")
            evt_wait.waitEvent(self.Running,
                               equal=False,
                               after=time_stamp,
                               timeout=self.InteractiveTimeout)
        finally:
            evt_wait.unlock()
            evt_wait.disconnect()

    def _clearRunMacro(self):
        # Clear the log buffer
        list(map(LogAttr.clearLogBuffer, list(self._log_attr.values())))
        self._running_macros = None
        self._running_macro = None
        self._user_xml = None
        self._block_lines = 0

    def _createMacroXml(self, macro_name, macro_params):
        """Creation of the macro XML object.

        :param macro_name: (str) macro name
        :param macro_params: (sequence[str]) list of parameter values,
            if repeat parameters are used parameter values may be sequences
            itself.
        :return (lxml.etree._Element) macro XML element
        """
        macro_info = self.macro_server.getMacroInfoObj(macro_name)
        params_def = macro_info.parameters
        macro_node = createMacroNode(macro_name, params_def, macro_params)
        return macro_node.toXml()

    def preRunMacro(self, obj, parameters):
        self._clearRunMacro()

        xml_root = None
        if isinstance(obj, str):
            if obj.startswith('<') and not parameters:
                xml_root = etree.fromstring(obj)
            else:
                macros = []
                if len(parameters) == 0:
                    macros_strs = obj.split('\n')
                    for m in macros_strs:
                        pars = m.split()
                        macros.append((pars[0], pars[1:]))
                else:
                    parameters = recur_map(str, parameters)
                    macros.append((obj, parameters))
                xml_root = xml_seq = etree.Element('sequence')
                for m in macros:
                    macro_name = m[0]
                    macro_params = m[1]
                    xml_macro = self._createMacroXml(macro_name, macro_params)
                    xml_macro.set('id', str(uuid.uuid1()))
                    xml_seq.append(xml_macro)
        elif etree.iselement(obj):
            xml_root = obj
        else:
            raise TypeError('obj must be a string or a etree.Element')

        self._running_macros = {}
        for macro_xml in xml_root.xpath('//macro'):
            id, name = macro_xml.get('id'), macro_xml.get('name')
            self._running_macros[id] = Macro(self, name, id, macro_xml)
        return xml_root

    def postRunMacro(self, result, synch):
        pass

    def runMacro(self, obj, parameters=[], synch=False):
        self._user_xml = self.preRunMacro(obj, parameters)
        result = self._runMacro(self._user_xml, synch=synch)
        return self.postRunMacro(result, synch)

    def _runMacro(self, xml, synch=False):
        if not synch:
            return self.command_inout(
                "RunMacro", [etree.tostring(xml, encoding='unicode')])
        timeout = self.InteractiveTimeout
        evt_wait = self._getEventWait()
        evt_wait.connect(self.getAttribute("state"))
        evt_wait.lock()
        try:
            evt_wait.waitEvent(self.Running, equal=False, timeout=timeout)
            # Clear event set to not confuse the value coming from the
            # connection with the event of of end of the macro execution
            # in the next wait event. This was observed on Windows where
            # the time stamp resolution is not better than 1 ms.
            evt_wait.clearEventSet()
            ts = time.time()
            result = self.command_inout(
                "RunMacro", [etree.tostring(xml, encoding='unicode')])
            evt_wait.waitEvent(self.Running, after=ts, timeout=timeout)
            if synch:
                evt_wait.waitEvent(self.Running,
                                   equal=False,
                                   after=ts,
                                   timeout=timeout)
        finally:
            self._clearRunMacro()
            evt_wait.unlock()
            evt_wait.disconnect()
        return result

    def stateChanged(self, s, t, v):
        # In contrary to the Taurus3 the Taurus4 raises exceptions when the
        # device server is getting down and we try to retrieve the state.
        # In this case provide the same behavior as Taurus3 - assign None to
        # the old state
        try:
            self._old_door_state = self.stateObj.rvalue
        except PyTango.DevFailed:
            self._old_door_state = None

        self._old_sw_door_state = self.state

    def resultReceived(self, log_name, result):
        """Method invoked by the arrival of a change event on the Result
        attribute"""
        if self._ignore_logs or self._running_macro is None:
            return
        self._running_macro.setResult(result)
        return result

    def putEnvironment(self, name, value):
        self.macro_server.putEnvironment(name, value)

    def putEnvironments(self, obj):
        self.macro_server.putEnvironments(obj)

    setEnvironment = putEnvironment
    setEnvironments = putEnvironments

    def getEnvironment(self, name=None):
        return self.macro_server.getEnvironment(name=name)

    def inputReceived(self, s, t, v):
        if t not in CHANGE_EVT_TYPES:
            return
        if v is None or self._running_macros is None:
            return
        input_data = CodecFactory().decode(('json', v.value))
        self.processInput(input_data)

    def processInput(self, input_data):
        TaurusManager().addJob(self._processInput, None, input_data)

    def _processInput(self, input_data):
        input_type = input_data['type']
        if input_type == 'input':
            result = self._input_handler.input(input_data)
            if result['input'] == '' and 'default_value' in input_data:
                result['input'] = input_data['default_value']
            result = CodecFactory().encode('json', ('', result))[1]
            self.write_attribute('Input', result)
        elif input_type == 'timeout':
            self._input_handler.input_timeout(input_data)

    def recordDataReceived(self, s, t, v):
        if t not in CHANGE_EVT_TYPES:
            return
        return self._processRecordData(v)

    def _processRecordData(self, data):
        if data is None or data.rvalue is None:
            return
        data = data.rvalue

        size = len(data[1])
        if size == 0:
            return
        format = data[0]
        codec = CodecFactory().getCodec(format)
        data = codec.decode(data)
        return data

    def processRecordData(self, data):
        pass

    def macroStatusReceived(self, s, t, v):
        if v is None or self._running_macros is None:
            return
        if t not in CHANGE_EVT_TYPES:
            return

        v = v.value
        if not len(v[1]):
            return
        format = v[0]
        codec = CodecFactory().getCodec(format)

        fmt, data = codec.decode(v)
        for macro_status in data:
            id = macro_status.get('id')
            macro = self._running_macros.get(id)
            self._last_running_macro = self._running_macro = macro
            # if we don't have the ID it's because the macro is running a
            # submacro or another client is connected to the same door (shame
            #  on him!) and executing a macro we discard this event
            if macro is not None:
                macro.__dict__.update(macro_status)
        return data

    def logReceived(self, log_name, output):
        term_size = get_terminal_size()
        max_chrs = term_size.columns if term_size else None
        if not output or self._silent or self._ignore_logs:
            return

        if log_name == self.Debug and not self._debug:
            return

        o = self.log_start[log_name]
        for line in output:
            if not self._debug:
                if line == self.BlockStart:
                    self._in_block = True
                    for i in range(self._block_lines):
                        if max_chrs is None:
                            nb_lines = 1
                        else:
                            nb_lines = _get_nb_lines(self._len_last_data_line,
                                                     max_chrs)
                        # per each line: erase current line,
                        # go up one line and erase current line
                        o += '\x1b[2K\x1b[1A\x1b[2K' * nb_lines
                    self._block_lines = 0
                    continue
                elif line == self.BlockFinish:
                    self._in_block = False
                    continue
                else:
                    self._len_last_data_line = len(line)
                    if self._in_block:
                        self._block_lines += 1
                    else:
                        self._block_lines = 0

            o += "%s\n" % line
        o += self.log_stop[log_name]
        self.write(o)

    def write(self, msg, stream=None):
        if self.isSilent():
            return
        self._output_stream = sys.stdout
        out = self._output_stream
        if stream is not None:
            start, stop = self.log_start.get(stream), self.log_stop.get(stream)
            if start is not None and stop is not None:
                out.write(start)
                out.write(msg)
                out.write(stop)
                out.flush()
                return
        out.write(msg)
        out.flush()

    def writeln(self, msg='', stream=None):
        self.write("%s\n" % msg, stream=stream)

    def getExperimentConfigurationObj(self):
        return self._experiment_configuration

    def getExperimentConfiguration(self):
        return self._experiment_configuration.get()

    def setExperimentConfiguration(self, config, mnt_grps=None):
        self._experiment_configuration.set(config, mnt_grps=mnt_grps)
Exemple #34
0
 def getElementsOfTypes(self, elem_types):
     elems = CaselessDict()
     for elem_type in elem_types:
         elems.update(self.getElementsOfType(elem_type))
     return elems
Exemple #35
0
class BaseSardanaElementContainer:

    def __init__(self):
        # dict<str, dict> where key is the type and value is:
        #     dict<str, MacroServerElement> where key is the element full name
        #                                   and value is the Element object
        self._type_elems_dict = CaselessDict()

        # dict<str, container> where key is the interface and value is the set
        # of elements which implement that interface
        self._interfaces_dict = {}

    def addElement(self, elem):
        elem_type = elem.getType()
        elem_full_name = elem.full_name

        # update type_elems
        type_elems = self._type_elems_dict.get(elem_type)
        if type_elems is None:
            self._type_elems_dict[elem_type] = type_elems = CaselessDict()
        type_elems[elem_full_name] = elem

        # update interfaces
        for interface in elem.interfaces:
            interface_elems = self._interfaces_dict.get(interface)
            if interface_elems is None:
                self._interfaces_dict[
                    interface] = interface_elems = CaselessDict()
            interface_elems[elem_full_name] = elem

    def removeElement(self, e):
        elem_type = e.getType()

        # update type_elems
        type_elems = self._type_elems_dict.get(elem_type)
        if type_elems:
            del type_elems[e.full_name]

        # update interfaces
        for interface in e.interfaces:
            interface_elems = self._interfaces_dict.get(interface)
            del interface_elems[e.full_name]

    def removeElementsOfType(self, t):
        for elem in self.getElementsOfType(t):
            self.removeElement(elem)

    def getElementsOfType(self, t):
        elems = self._type_elems_dict.get(t, {})
        return elems

    def getElementNamesOfType(self, t):
        return [e.name for e in self.getElementsOfType(t).values()]

    def getElementsWithInterface(self, interface):
        elems = self._interfaces_dict.get(interface, {})
        return elems

    def getElementsWithInterfaces(self, interfaces):
        ret = CaselessDict()
        for interface in interfaces:
            ret.update(self.getElementsWithInterface(interface))
        return ret

    def getElementNamesWithInterface(self, interface):
        return [e.name for e in self.getElementsWithInterface(interface).values()]

    def hasElementName(self, elem_name):
        return self.getElement(elem_name) is not None

    def getElement(self, elem_name):
        elem_name = elem_name.lower()
        for elems in self._type_elems_dict.values():
            elem = elems.get(elem_name)  # full_name?
            if elem is not None:
                return elem
            for elem in elems.values():
                if elem.name.lower() == elem_name:
                    return elem

    def getElementWithInterface(self, elem_name, interface):
        elem_name = elem_name.lower()
        elems = self._interfaces_dict.get(interface, {})
        if elem_name in elems:
            return elems[elem_name]
        for elem in elems.values():
            if elem.name.lower() == elem_name:
                return elem

    def getElements(self):
        ret = set()
        for elems in self._type_elems_dict.values():
            ret.update(elems.values())
        return ret

    def getInterfaces(self):
        return self._interfaces_dict

    def getTypes(self):
        return self._type_elems_dict
Exemple #36
0
class ImageCounterDevice(ImageDevice):
    """A class encapsulating a generic image device that has an image counter
    attribute"""

    def __init__(self, name, image_name='image', image_ct='imagecounter', **kw):
        self._image_data = CaselessDict()
        self._image_id_attr_name = image_ct
        self.call__init__(ImageDevice, name, image_name, **kw)
        self._busy = False
        self._image_id_attr = self.getAttribute(self._image_id_attr_name)
        self._image_id_attr.addListener(self)

    def _setDirty(self, names=None):
        names = names or self.getImageAttrNames()
        for n in names:
            d = self._image_data.get(n, (True, None))
            self._image_data[n] = True, d[1]

    def _getDirty(self, names=None):
        names = names or self.getImageAttrNames()
        dirty = []
        for name in names:
            d = self._image_data.get(name)
            if d is None or d[0] == True:
                dirty.append(name)
        return names

    def getImageIDAttrName(self):
        return self._image_id_attr_name

    def eventReceived(self, evt_src, evt_type, evt_value):
        if evt_src == self._image_id_attr:
            if evt_type == TaurusEventType.Change:
                # discard events if there is one being processed
                if not self._busy:
                    self._busy = True
                    self.debug("Processing image %d" % evt_value.rvalue)
                    # read the related Image attributes
                    # (asap and in one action)
                    images = self.getImageData()
                    self._setDirty()
                    self.fireEvent(evt_type, evt_value)
                    # maintain this fireEvent for backwards compatibility
                    # with Qub widget
                    self._emitImageEvents(evt_type, images)
                    self._busy = False
                else:
                    self.debug("Discard image %d" % evt_value.value)
        else:
            ImageDevice.eventReceived(self, evt_src, evt_type, evt_value)

    def _emitImageEvents(self, evt_type, images):
        for attr_image_name in images:
            image_value = images[attr_image_name][1]
            if hasattr(image_value, 'is_empty') and not image_value.is_empty:
                self.debug("fireEvent for %s attribute" % attr_image_name)
                if not hasattr(image_value, 'rvalue'):
                    image_value.rvalue = image_value.value
                # Only emit to upper layers the events where
                # something has been read.
                attr_image = self.getAttribute(image_value.name)
                attr_image.fireEvent(evt_type, image_value)

    def getImageData(self, names=None):
        if names is None:
            names = self.getImageAttrNames()
        elif isinstance(names, str):
            names = (names,)

        fetch = self._getDirty(names)

        try:
            data = self.read_attributes(fetch)
            for d in data:
                self._image_data[d.name] = False, d
        except:
            pass
        return self._image_data
Exemple #37
0
 def getElementsWithInterfaces(self, interfaces):
     ret = CaselessDict()
     for interface in interfaces:
         ret.update(self.getElementsWithInterface(interface))
     return ret
Exemple #38
0
class ImageCounterDevice(ImageDevice):
    """A class encapsulating a generic image device that has an image counter
    attribute"""
    def __init__(self,
                 name,
                 image_name='image',
                 image_ct='imagecounter',
                 **kw):
        self.lock = Lock()
        self._image_data = CaselessDict()
        self._image_id_attr_name = image_ct
        self.call__init__(ImageDevice, name, image_name, **kw)
        self.image_attr = self.getAttribute(image_name)
        self._image_id_attr = self.getAttribute(self._image_id_attr_name)
        self.discard_event = False
        self._image_id_attr.addListener(self)

    def _setDirty(self, names=None):
        names = names or self.getImageAttrNames()
        for n in names:
            d = self._image_data.get(n, (True, None))
            self._image_data[n] = True, d[1]

    def _getDirty(self, names=None):
        names = names or self.getImageAttrNames()
        dirty = []
        for name in names:
            d = self._image_data.get(name)
            if d is None or d[0] is True:
                dirty.append(name)
        return names

    def getImageIDAttrName(self):
        return self._image_id_attr_name

    def eventReceived(self, evt_src, evt_type, evt_value):
        if evt_src == self._image_id_attr:
            if evt_type == TaurusEventType.Change:

                # discard events if there is one being processed
                if self.lock.locked():
                    self.discard_event = True
                    self.debug("Discard event %d" % evt_value.value)
                    return

                with self.lock:
                    while True:
                        self.debug("Processing image %d" % evt_value.rvalue)
                        # read the related Image attributes
                        # (asap and in one action)
                        images = self.getImageData()
                        self._setDirty()
                        self.fireEvent(evt_type, evt_value)
                        # maintain this fireEvent for backwards compatibility
                        # with Qub widget
                        self._emitImageEvents(evt_type, images)

                        if self.discard_event:
                            self.discard_event = False
                        else:
                            break
        else:
            ImageDevice.eventReceived(self, evt_src, evt_type, evt_value)

    def _emitImageEvents(self, evt_type, images):
        for attr_image_name in images:
            image_value = images[attr_image_name][1]
            if hasattr(image_value, 'is_empty') and not image_value.is_empty:
                self.debug("fireEvent for %s attribute" % attr_image_name)
                if not hasattr(image_value, 'rvalue'):
                    image_value.rvalue = image_value.value
                # Only emit to upper layers the events where
                # something has been read.
                attr_image = self.getAttribute(image_value.name)
                attr_image.fireEvent(evt_type, image_value)

    def getImageData(self, names=None):
        if names is None:
            names = self.getImageAttrNames()
        elif isinstance(names, string_types):
            names = (names, )

        fetch = self._getDirty(names)

        try:
            data = self.read_attributes(fetch)
            for d in data:
                self._image_data[d.name] = False, d
        except:
            pass
        return self._image_data
Exemple #39
0
class ReadTangoAttributes(object):
    """ Generic class that has as many devices as the user wants.
    Each device has a tango attribute and a formula and the 'hardware' tango calls
    are optimized in the sense that only one call per tango device is issued.
    """
    axis_attributes = {
        TangoAttribute: {
            Type: str,
            Access: DataAccess.ReadWrite,
            Description: 'Attribute to read (e.g. a/b/c/attr)'
        },
        Formula: {
            Type:
            str,
            Access:
            DataAccess.ReadWrite,
            DefaultValue:
            "VALUE",
            Description:
            'The Formula to get the desired value.\n'
            'e.g. "math.sqrt(VALUE)"'
        },
    }

    def __init__(self):
        #: dict<int(axis), str(reason for being in pending)>
        self._pending = {}

        #: dict<str(dev name), tuple<DeviceProxy, list<str(attributes name)>>>
        self._devices = CaselessDict()

        #: dict<int(axis), seq<str<tango full attribute name>, str<attr name>, DeviceProxy>>
        self._axis_tango_attributes = {}

        #: dict<int(axis), str<formula>>
        self._axis_formulas = {}

    def add_device(self, axis):
        self._pending[
            axis] = "No tango attribute associated to this device yet"
        self._axis_formulas[axis] = self.axis_attribute[Formula][DefaultValue]

    def delete_device(self, axis):
        if axis in self._pending:
            del self._pending[axis]
        else:
            del self._axis_tango_attributes[axis]
            del self._axis_formulas[axis]

    def state_one(self, axis):
        pending_info = self._pending.get(axis)
        if pending_info is not None:
            return State.Fault, pending_info
        return State.On, 'Always ON, just reading tango attribute'

    def pre_read_all(self):
        self._devices_read = {}

    def pre_read_one(self, axis):
        attr_name, dev = self._axis_tango_attributes[axis][1:]
        dev_attrs = self._devices_read.get(dev)
        if dev_attrs is None:
            self._
            self._devices_read[dev] = dev_attrs = []
        dev_attrs.append(attr_name)

    def read_all(self):
        pass

    def read_one(self, axis):
        pass

    def get_extra_attribute_par(self, axis, name):
        if name == TangoAttribute:
            return self._axis_tango_attributes[axis][0]
        elif name == Formula:
            return self._axis_formulas[axis]

    def set_extra_attribute_par(self, axis, name, value):
        if name == TangoAttribute:
            value = value.lower()
            self._axis_tango_attributes[axis] = data = value, None, None
            try:
                dev_name, attr_name = value.rsplit("/", 1)
                data[1] = attr_name
            except:
                self._pending[axis] = "invalid device name " + value
                raise Exception(self._pending[axis])
            dev_info = self._devices.get(dev_name)
            if dev_info is None:
                try:
                    proxy = PyTango.DeviceProxy(dev_name)
                except PyTango.DevFailed, df:
                    if len(df):
                        self._pending[axis] = df[0].reason + ": " + df[0].desc
                    else:
                        self._pending[axis] = "Unknwon PyTango Error: " + str(
                            df)
                    raise
                self._devices[dev_name] = dev_info = proxy, []
            data[2] = dev_info[0]
            dev_info[1].append(attr_name)

        elif name == Formula:
            self._axis_formulas[axis] = value
Exemple #40
0
    def remove_unwanted_dynamic_attributes(self, new_std_attrs, new_dyn_attrs):
        """Removes unwanted dynamic attributes from previous device creation"""

        dev_class = self.get_device_class()
        multi_attr = self.get_device_attr()
        multi_class_attr = dev_class.get_class_attr()
        static_attr_names = map(str.lower, dev_class.attr_list.keys())
        static_attr_names.extend(('state', 'status'))

        new_attrs = CaselessDict(new_std_attrs)
        new_attrs.update(new_dyn_attrs)

        device_attr_names = []
        for i in range(multi_attr.get_attr_nb()):
            device_attr_names.append(multi_attr.get_attr_by_ind(i).get_name())

        for attr_name in device_attr_names:
            attr_name_lower = attr_name.lower()
            if attr_name_lower in static_attr_names:
                continue
            try:
                self.remove_attribute(attr_name)
            except:
                self.warning("Error removing dynamic attribute %s",
                             attr_name_lower)
                self.debug("Details:", exc_info=1)

        klass_attr_names = []
        klass_attrs = multi_class_attr.get_attr_list()
        for ind in range(len(klass_attrs)):
            klass_attr_names.append(klass_attrs[ind].get_name())

        for attr_name in klass_attr_names:
            attr_name_lower = attr_name.lower()
            if attr_name_lower in static_attr_names:
                continue
            # if new dynamic attribute is in class attribute then delete it
            # from class attribute to be later on added again (eventually
            # with diffent data type or data format)
            if attr_name_lower in new_attrs:
                try:
                    attr = multi_class_attr.get_attr(attr_name)

                    old_type = CmdArgType(attr.get_type())
                    old_format = attr.get_format()
                    old_access = attr.get_writable()

                    new_attr = new_attrs[attr_name]
                    new_type, new_format, new_access = new_attr[1][0][:3]
                    differ = new_type != old_type or \
                             new_format != old_format or \
                             new_access != old_access
                    if differ:
                        self.info("Replacing dynamic attribute %s", attr_name)
                        self.debug("old type: %s, new type: %s", old_type,
                                   new_type)
                        self.debug("old format: %s, new format: %s",
                                   old_format, new_format)
                        self.debug("old access: %s, new access: %s",
                                   old_access, new_access)
                        multi_class_attr.remove_attr(attr.get_name(),
                                                     attr.get_cl_name())
                except:
                    self.warning("Error removing dynamic attribute %s from "\
                                 " device class", attr_name)
                    self.debug("Details:", exc_info=1)
Exemple #41
0
class MacroServer(MSContainer, MSObject, SardanaElementManager,
                  SardanaIDManager):

    All = "All"

    MaxParalellMacros = 5

    logReportParams = dict(when='midnight', interval=1, backupCount=365)
    logReportKlass = NonOverlappingTimedRotatingFileHandler

    def __init__(self,
                 full_name,
                 name=None,
                 macro_path=None,
                 environment_db=None,
                 recorder_path=None):
        # dict<str, Pool>
        # key   - device name (case insensitive)
        # value - Pool object representing the device name
        self._pools = CaselessDict()
        self._max_parallel_macros = self.MaxParalellMacros
        self._path_id = None

        MSContainer.__init__(self)
        MSObject.__init__(self,
                          full_name=full_name,
                          name=name,
                          id=InvalidId,
                          macro_server=self,
                          elem_type=ElementType.MacroServer)

        registerExtensions()

        self._type_manager = TypeManager(self)
        self._environment_manager = EnvironmentManager(
            self, environment_db=environment_db)
        self._macro_manager = MacroManager(self, macro_path=macro_path)
        self._recorder_manager = RecorderManager(self,
                                                 recorder_path=recorder_path)

    def serialize(self, *args, **kwargs):
        kwargs = MSObject.serialize(self, *args, **kwargs)
        kwargs['type'] = self.__class__.__name__
        kwargs['id'] = InvalidId
        kwargs['parent'] = None
        return kwargs

    def add_job(self, job, callback=None, *args, **kw):
        th_pool = get_thread_pool()
        th_pool.add(job, callback, *args, **kw)

    # --------------------------------------------------------------------------
    # Environment DB related methods
    # --------------------------------------------------------------------------

    def set_environment_db(self, environment_db):
        """Sets the environment database.

        :param env_db:
            environment database name
        :type env_db:
            str
        """
        self.environment_manager.setEnvironmentDb(environment_db)

    # --------------------------------------------------------------------------
    # Python related methods
    # --------------------------------------------------------------------------

    def set_python_path(self, path):
        mod_man = ModuleManager()
        if self._path_id is not None:
            mod_man.remove_python_path(self._path_id)
        self._path_id = mod_man.add_python_path(path)

    # --------------------------------------------------------------------------
    # Macro path related methods
    # --------------------------------------------------------------------------

    def set_macro_path(self, macro_path):
        """Sets the macro path.

        :param macro_path:
            macro path
        :type macro_path:
            seq<str>
        """
        self.macro_manager.setMacroPath([p.rstrip(os.sep) for p in macro_path])

    # --------------------------------------------------------------------------
    # Recorder path related methods
    # --------------------------------------------------------------------------

    def set_recorder_path(self, recorder_path):
        """Sets the recorder path.

        :param recorder_path:
            recorder path
        :type recorder_path:
            seq<str>
        """
        self.recorder_manager.setRecorderPath(recorder_path)

    # --------------------------------------------------------------------------
    # Report related methods
    # --------------------------------------------------------------------------

    def set_log_report(self, filename=None, format=None):
        log = self.get_report_logger()

        # first check that the handler has not been initialized yet. If it has
        # we remove previous handlers. We only allow one timed rotating file
        # handler at a time
        to_remove = []
        for handler in log.handlers:
            if isinstance(handler, logging.handlers.TimedRotatingFileHandler):
                to_remove.append(handler)

        for handler in to_remove:
            handler.close()
            log.removeHandler(handler)

        if filename is None:
            return

        if format is None:
            format = Logger.DftLogMessageFormat
        formatter = logging.Formatter(format)

        self.info("Reports are being stored in %s", filename)
        klass = self.logReportKlass
        handler = klass(filename, **self.logReportParams)
        handler.setFormatter(formatter)
        log.addHandler(handler)

    def clear_log_report(self):
        self.set_log_report()

    def get_report_logger(self):
        return logging.getLogger("Sardana.Report")

    report_logger = property(get_report_logger)

    def report(self, msg, *args, **kwargs):
        """
        Record a log message in the sardana report (if enabled) with default
        level **INFO**. The msg is the message format string, and the args are
        the arguments which are merged into msg using the string formatting
        operator. (Note that this means that you can use keywords in the
        format string, together with a single dictionary argument.)

        *kwargs* are the same as :meth:`logging.Logger.debug` plus an optional
        level kwargs which has default value **INFO**

        Example::

            self.report("this is an official report!")

        :param msg: the message to be recorded
        :type msg: :obj:`str`
        :param args: list of arguments
        :param kwargs: list of keyword arguments"""
        level = kwargs.pop('level', logging.INFO)
        return self.report_logger.log(level, msg, *args, **kwargs)

    # --------------------------------------------------------------------------
    # Pool related methods
    # --------------------------------------------------------------------------

    def set_pool_names(self, pool_names):
        """Registers a new list of device pools in this manager

        :param pool_names: sequence of pool names
        :type pool_names: seq<str>"""
        for pool in self._pools.values():
            elements_attr = pool.getAttribute("Elements")
            elements_attr.removeListener(self.on_pool_elements_changed)

        for name in pool_names:
            self.debug("Creating pool %s", name)
            pool = Device(name)
            if pool is None:
                self.error('Could not create Pool object for %s' % name)
                continue
            self._pools[name] = pool
            elements_attr = pool.getAttribute("Elements")
            elements_attr.addListener(self.on_pool_elements_changed)

    def get_pool_names(self):
        """Returns the list of names of the pools this macro server is connected
        to.

        :return:
            the list of names of the pools this macro server is connected to
        :rtype:
            seq<str>"""
        return self._pools.keys()

    def get_pool(self, pool_name):
        """Returns the device pool object corresponding to the given device name
        or None if no match is found.

        :param pool_name: device pool name
        :type pool_name: str
        :return: Pool object or None if no match is found"""
        return self._pools.get(pool_name)

    def get_pools(self):
        """Returns the list of pools this macro server is connected to.

        :return: the list of pools this macro server is connected to
        :rtype: seq<Pool>"""
        return self._pools.values()

    def on_pool_elements_changed(self, evt_src, evt_type, evt_value):
        if evt_type not in CHANGE_EVT_TYPES:
            return
        self.fire_event(EventType("PoolElementsChanged"), evt_value)

    # --------------------------------------------------------------------------
    # Door related methods
    # --------------------------------------------------------------------------

    def create_element(self, **kwargs):
        type = kwargs['type']
        elem_type = ElementType[type]
        name = kwargs['name']

        kwargs['macro_server'] = self

        td = TYPE_MAP_OBJ[elem_type]
        klass = td.klass
        auto_full_name = td.auto_full_name

        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))

        self.check_element(name, full_name)

        id = kwargs.get('id')
        if id is None:
            kwargs['id'] = id = self.get_new_id()
        else:
            self.reserve_id(id)
        elem = klass(**kwargs)
        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def create_door(self, **kwargs):
        return self.create_element(type="Door", **kwargs)

    # --------------------------------------------------------------------------
    # General access to elements
    # --------------------------------------------------------------------------

    def get_elements_info(self):
        return self.get_remote_elements_info() + self.get_local_elements_info()

    def get_remote_elements_info(self):
        return [
            elem.serialize() for pool in self.get_pools()
            for elem in pool.getElements()
        ]

    def get_local_elements_info(self):
        # fill macro library info
        ret = [
            macrolib.serialize()
            for macrolib in self.get_macro_libs().values()
        ]
        # fill macro info
        ret += [macro.serialize() for macro in self.get_macros().values()]
        # fill parameter type info
        ret += [
            paramtype.serialize()
            for paramtype in self.get_data_types().values()
        ]

        return ret

    # --------------------------------------------------------------------------
    # macro execution
    # --------------------------------------------------------------------------

    def set_max_parallel_macros(self, nb):
        assert nb > 0, "max parallel macros number must be > 0"
        th_pool = get_thread_pool()
        if th_pool.size + 5 < nb:
            th_pool.size = nb
        self._max_parallel_macros = nb

    def get_max_parallel_macros(self):
        return self._max_parallel_macros

    max_parallel_macros = property(get_max_parallel_macros,
                                   set_max_parallel_macros,
                                   doc="maximum number of macros which can "
                                   "execute at the same time")

    @property
    def macro_manager(self):
        return self._macro_manager

    @property
    def recorder_manager(self):
        return self._recorder_manager

    @property
    def environment_manager(self):
        return self._environment_manager

    @property
    def type_manager(self):
        return self._type_manager

    # --------------------------------------------------------------------------
    # (Re)load code
    # --------------------------------------------------------------------------

    def reload_lib(self, lib_name):
        return self.macro_manager.reloadLib(lib_name)

    def reload_macro_lib(self, lib_name):
        manager = self.macro_manager

        try:
            old_lib = manager.getMacroLib(lib_name)
        except UnknownMacroLibrary:
            old_lib = None

        new_elements, changed_elements, deleted_elements = [], [], []

        new_lib = manager.reloadMacroLib(lib_name)
        if new_lib.has_errors():
            return new_lib

        if old_lib is None:
            new_elements.extend(new_lib.get_macros())
            new_elements.append(new_lib)
        else:
            changed_elements.append(new_lib)
            new_names = set([macro.name for macro in new_lib.get_macros()])
            old_names = set([macro.name for macro in old_lib.get_macros()])
            changed_names = set.intersection(new_names, old_names)
            deleted_names = old_names.difference(new_names)
            new_names = new_names.difference(old_names)

            for new_name in new_names:
                new_elements.append(new_lib.get_macro(new_name))
            for changed_name in changed_names:
                changed_elements.append(new_lib.get_macro(changed_name))
            for deleted_name in deleted_names:
                deleted_elements.append(old_lib.get_macro(deleted_name))

        evt = {
            "new": new_elements,
            "change": changed_elements,
            "del": deleted_elements
        }
        self.fire_event(EventType("ElementsChanged"), evt)
        return new_lib

    reload_macro_lib.__doc__ = MacroManager.reloadMacroLib.__doc__

    def reload_macro_libs(self, lib_names):
        for lib_name in lib_names:
            self.reload_macro_lib(lib_name)

    def reload_macro(self, macro_name):
        macro_info = self.macro_manager.getMacro(macro_name)
        lib_name = macro_info.module_name
        return self.reload_macro_lib(lib_name)

    def reload_macros(self, macro_names):
        lib_names = set()
        for macro_name in macro_names:
            macro_info = self.macro_manager.getMacro(macro_name)
            lib_names.add(macro_info.module_name)
        self.reload_macro_libs(lib_names)

    def get_macro_lib(self, lib_name):
        return self.macro_manager.getMacroLib(lib_name)

    get_macro_lib.__doc__ = MacroManager.getMacroLib.__doc__

    def get_macro_libs(self, filter=None):
        return self.macro_manager.getMacroLibs(filter=filter)

    get_macro_libs.__doc__ = MacroManager.getMacroLibs.__doc__

    def get_macro_lib_names(self):
        return self.macro_manager.getMacroLibNames()

    get_macro_lib_names.__doc__ = MacroManager.getMacroLibNames.__doc__

    def get_macro(self, name):
        return self.macro_manager.getMacro(name)

    get_macro.__doc__ = MacroManager.getMacro.__doc__

    def get_macros(self, filter=None):
        return self.macro_manager.getMacros(filter=filter)

    get_macros.__doc__ = MacroManager.getMacros.__doc__

    def get_macro_names(self):
        return self.macro_manager.getMacroNames()

    get_macro_names.__doc__ = MacroManager.getMacroNames.__doc__

    def get_macro_classes(self):
        return self.macro_manager.getMacroClasses()

    get_macro_classes.__doc__ = MacroManager.getMacroClasses.__doc__

    def get_macro_functions(self):
        return self.macro_manager.getMacroFunctions()

    get_macro_functions.__doc__ = MacroManager.getMacroFunctions.__doc__

    def get_macro_libs_summary_info(self):
        libs = self.get_macro_libs()
        ret = []
        for module_name, macro_lib_info in libs.items():
            elem = "%s (%s)" % (macro_lib_info.name, macro_lib_info.file_path)
            ret.append(elem)
        return ret

    def get_macro_classes_summary_info(self):
        macros = self.get_macros()
        ret = []
        for macro_info in macros:
            elem = "%s (%s)" % (macro_info.name, macro_info.file_path)
            ret.append(elem)
        return ret

    def get_or_create_macro_lib(self, lib_name, macro_name=None):
        """Gets the exiting macro lib or creates a new macro lib file. If
        name is not None, a macro template code for the given macro name is
        appended to the end of the file.

        :param lib_name:
            module name, python file name, or full file name (with path)
        :type lib_name: str
        :param macro_name:
            an optional macro name. If given a macro template code is appended
            to the end of the file (default is None meaning no macro code is
            added)
        :type macro_name: str

        :return:
            a sequence with three items: full_filename, code, line number is 0
            if no macro is created or n representing the first line of code for
            the given macro name.
        :rtype: seq<str, str, int>"""
        return self.macro_manager.getOrCreateMacroLib(lib_name,
                                                      macro_name=macro_name)

    get_or_create_macro_lib.__doc__ = MacroManager.getOrCreateMacroLib.__doc__

    def set_macro_lib(self, lib_name, code, auto_reload=True):
        module_name = self.macro_manager.setMacroLib(lib_name,
                                                     code,
                                                     auto_reload=False)
        if auto_reload:
            self.reload_macro_lib(module_name)

    set_macro_lib.__doc__ = MacroManager.setMacroLib.__doc__

    # --------------------------------------------------------------------------
    # Data types
    # --------------------------------------------------------------------------

    def get_data_types(self):
        return self.type_manager.getTypes()

    get_data_types.__doc__ = TypeManager.getTypes.__doc__

    def get_data_type(self, type_name):
        return self.type_manager.getTypeObj(type_name)

    get_data_type.__doc__ = TypeManager.getTypeObj.__doc__

    def get_data_type_names(self):
        return self.type_manager.getTypeNames()

    get_data_type_names.__doc__ = TypeManager.getTypeNames.__doc__

    def get_data_type_names_with_asterisc(self):
        return self.type_manager.getTypeListStr()

    get_data_type_names_with_asterisc.__doc__ = TypeManager.getTypeListStr.__doc__

    # --------------------------------------------------------------------------
    # Doors
    # --------------------------------------------------------------------------

    def get_doors(self):
        return self.get_elements_by_type(ElementType.Door)

    def get_door_names(self):
        return [door.full_name for door in self.get_doors()]

    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
    # Environment access methods
    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-

    def get_env(self, key=None, door_name=None, macro_name=None):
        """Gets the environment matching the given parameters:

               - door_name and macro_name define the context where to look for
                 the environment. If both are None, the global environment is
                 used. If door name is None but macro name not, the given macro
                 environment is used and so on...
               - If key is None it returns the complete environment, otherwise
                 key must be a string containing the environment variable name.

        :param key:
            environment variable name [default: None, meaning all environment]
        :type key: str
        :param door_name:
            local context for a given door [default: None, meaning no door
            context is used]
        :type door_name: str
        :param macro_name:
            local context for a given macro [default: None, meaning no macro
            context is used]
        :type macro_name: str

        :return: a :obj:`dict` containing the environment
        :rtype: :obj:`dict`

        :raises: UnknownEnv"""
        return self.environment_manager.getEnv(key=key,
                                               macro_name=macro_name,
                                               door_name=door_name)

    def set_env(self, key, value):
        """Sets the environment key to the new value and stores it persistently.

        :param key: the key for the environment
        :param value: the value for the environment

        :return: a tuple with the key and value objects stored"""
        env_man = self.environment_manager
        if env_man.hasEnv(key):
            evt_type = "change"
        else:
            evt_type = "new"

        k, v = self.environment_manager.setEnv(key, value)

        evt = {evt_type: {k: v}}
        self.fire_event(EventType("EnvironmentChanged"), evt)
        return k, v

    def set_env_obj(self, data):
        """Sets the environment key to the new value and stores it persistently.

        :param key: the key for the environment
        :param value: the value for the environment

        :return: a tuple with the key and value objects stored"""
        env_man = self.environment_manager

        new, change = {}, {}
        for key, value in data.items():
            d = new
            if env_man.hasEnv(key):
                d = change
            d[key] = value

        ret = env_man.setEnvObj(data)

        evt = dict(new=new, change=change)
        self.fire_event(EventType("EnvironmentChanged"), evt)
        return ret

    def change_env(self, data):
        env_man = self.environment_manager
        new_change_env = data.get('new', {})
        new_change_env.update(data.get('change', {}))
        del_env = data.get('del', [])

        new, change = {}, {}
        for key, value in new_change_env.items():
            d = new
            if env_man.hasEnv(key):
                d = change
            d[key] = value

        del_keys = env_man.unsetEnv(del_env)
        env_man.setEnvObj(new_change_env)

        evt = dict(new=new, change=change)
        evt['del'] = del_keys
        self.fire_event(EventType("EnvironmentChanged"), evt)

    def unset_env(self, key):
        """Unsets the environment for the given key.

        :param key: the key for the environment to be unset"""
        ret = self.environment_manager.unsetEnv(key)
        # list is unhashable - convert to a tuple
        if isinstance(key, list):
            key = tuple(key)
        evt = {'del': {key: None}}
        self.fire_event(EventType("EnvironmentChanged"), evt)
        return ret

    def has_env(self, key, macro_name=None, door_name=None):
        return self.environment_manager.hasEnv(key,
                                               macro_name=macro_name,
                                               door_name=door_name)

    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
    # General object access methods
    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-

    def get_object(self, name, type_class=All, subtype=All, pool=All):
        objs = self.find_objects(name, type_class, subtype, pool)
        if len(objs) == 0:
            return None
        if len(objs) > 1:
            raise AttributeError('More than one object named "%s" found' %
                                 name)
        return objs[0]

    def get_objects(self, names, type_class=All, subtype=All, pool=All):
        return self.find_objects(names,
                                 type_class=type_class,
                                 subtype=subtype,
                                 pool=pool)

    def find_objects(self, param, type_class=All, subtype=All, pool=All):
        if is_pure_str(param):
            param = param,

        if type_class == MacroServer.All:
            type_name_list = self.get_data_type_names()
        else:
            if is_pure_str(type_class):
                type_name_list = type_class,
            else:
                type_name_list = type_class
        obj_set = set()
        param = ['^%s$' % x for x in param]
        re_objs = map(re.compile, param, len(param) * (re.IGNORECASE, ))
        re_subtype = re.compile(subtype, re.IGNORECASE)
        for type_name in type_name_list:
            type_class_name = type_name
            if type_class_name.endswith('*'):
                type_class_name = type_class_name[:-1]
            type_inst = self.get_data_type(type_class_name)
            if not type_inst.hasCapability(ParamType.ItemList):
                continue
            if self.is_macroserver_interface(type_class_name):
                for name, obj in type_inst.getObjDict(pool=pool).items():
                    for re_obj in re_objs:
                        if re_obj.match(name) is not None:
                            obj_type = ElementType[obj.get_type()]
                            if subtype is MacroServer.All or re_subtype.match(
                                    obj_type):
                                obj_set.add(obj)
            else:
                for name, obj in type_inst.getObjDict(pool=pool).items():
                    for re_obj in re_objs:
                        if re_obj.match(name) is not None:
                            obj_type = obj.getType()
                            if (subtype is MacroServer.All or
                                re_subtype.match(obj.getType())) and \
                               obj_type != "MotorGroup":
                                obj_set.add(obj)
        return list(obj_set)

    def get_motion(self,
                   elems,
                   motion_source=None,
                   read_only=False,
                   cache=True,
                   decoupled=False):
        if motion_source is None:
            motion_source = self.get_pools()

        motion_klass = Motion
        if decoupled:  # and len(elems)>1:
            motion_klass = MotionGroup
        return motion_klass(elems, motion_source)

    _LOCAL_INTERFACES = {
        Interface.MacroLibrary: get_macro_libs,
        Interface.MacroCode: get_macros,
        Interface.MacroClass: get_macro_classes,
        Interface.MacroFunction: get_macro_functions,
    }

    def is_macroserver_interface(self, interface):
        if is_pure_str(interface):
            interface = Interface[interface]
        return interface in self._LOCAL_INTERFACES

    def get_elements_with_interface(self, interface):
        ret = CaselessDict()
        if is_pure_str(interface):
            interface_str = interface
            interface = Interface[interface_str]
        else:
            interface_str = Interface[interface]

        if self.is_macroserver_interface(interface):
            ret.update(self._LOCAL_INTERFACES.get(interface)(self))
        else:
            for pool in self.get_pools():
                ret.update(pool.getElementsWithInterface(interface_str))
        return ret

    def get_element_with_interface(self, name, interface):
        for pool in self.get_pools():
            element = pool.getElementWithInterface(name, interface)
            if element is not None:
                return element

    def get_controllers(self):
        return self.get_elements_with_interface("Controller")

    def get_moveables(self):
        return self.get_elements_with_interface("Moveable")

    def get_motors(self):
        return self.get_elements_with_interface("Motor")

    def get_pseudo_motors(self):
        return self.get_elements_with_interface("PseudoMotor")

    def get_io_registers(self):
        return self.get_elements_with_interface("IORegister")

    def get_measurement_groups(self):
        return self.get_elements_with_interface("MeasurementGroup")

    def get_exp_channels(self):
        return self.get_elements_with_interface("ExpChannel")

    def get_counter_timers(self):
        return self.get_elements_with_interface("CTExpChannel")

    def get_0d_exp_channels(self):
        return self.get_elements_with_interface("ZeroDExpChannel")

    def get_1d_exp_channels(self):
        return self.get_elements_with_interface("OneDExpChannel")

    def get_2d_exp_channels(self):
        return self.get_elements_with_interface("TwoDExpChannel")

    def get_pseudo_counters(self):
        return self.get_elements_with_interface("PseudoCounter")

    def get_instruments(self):
        return self.get_elements_with_interface("Instrument")

    def get_controller(self, name):
        return self.get_element_with_interface(name, "Controller")

    def get_moveable(self, name):
        return self.get_element_with_interface(name, "Moveable")

    def get_motor(self, name):
        return self.get_element_with_interface(name, "Motor")

    def get_pseudo_motor(self, name):
        return self.get_element_with_interface(name, "PseudoMotor")

    def get_io_register(self, name):
        return self.get_element_with_interface(name, "IORegister")

    def get_measurement_group(self, name):
        return self.get_element_with_interface(name, "MeasurementGroup")

    def get_exp_channel(self, name):
        return self.get_element_with_interface(name, "ExpChannel")

    def get_counter_timer(self, name):
        return self.get_element_with_interface(name, "CTExpChannel")

    def get_0d_exp_channel(self, name):
        return self.get_element_with_interface(name, "ZeroDExpChannel")

    def get_1d_exp_channel(self, name):
        return self.get_element_with_interface(name, "OneDExpChannel")

    def get_2d_exp_channel(self, name):
        return self.get_element_with_interface(name, "TwoDExpChannel")

    def get_pseudo_counter(self, name):
        return self.get_element_with_interface(name, "PseudoCounter")

    def get_instrument(self, name):
        return self.get_element_with_interface(name, "Instrument")
Exemple #42
0
class TangoFactory(Singleton, TaurusFactory, Logger):
    """A :class:`TaurusFactory` singleton class to provide Tango-specific
    Taurus Element objects (TangoAuthority, TangoDevice, TangoAttribute)

    Tango model names are URI based See https://tools.ietf.org/html/rfc3986.
    For example, a TangoAttribute would be::

        tango://foo.org:1234/a/b/c/d#label
        \___/   \_____/ \__/ \_____/ \___/
          |        |     |      |      |
          |    hostname port  attr     |
          |   \____________/\______/   |
          |         |           |      |
        scheme   authority     path  fragment

    For Tango Elements:

        - The 'scheme' must be the string "tango" (lowercase mandatory)
        - The 'authority' identifies the Tango database (<hostname> and <port>
          are mandatory if authority is given)
        - The 'path' identifies Tango Device and Attributes.
          For devices it must have the format _/_/_ or alias
          For attributes it must have the format _/_/_/_ or devalias/_
        - The 'fragment' is optional and it refers to a member of the model
          object, thus not being part of the model name itself
    """

    #: the list of schemes that this factory supports. For this factory: 'tango'
    #: is the only scheme
    schemes = ("tango",)
    caseSensitive = False
    elementTypesMap = {TaurusElementType.Authority: TangoAuthority,
                       TaurusElementType.Device: TangoDevice,
                       TaurusElementType.Attribute: TangoAttribute
                       }

    def __init__(self):
        """ Initialization. Nothing to be done here for now."""
        pass

    def init(self, *args, **kwargs):
        """Singleton instance initialization.
           **For internal usage only**"""
        name = self.__class__.__name__
        self.call__init__(Logger, name)
        self.call__init__(TaurusFactory)
        self._polling_enabled = True
        self.reInit()
        self.scheme = 'tango'

    def reInit(self):
        """Reinitialize the singleton"""
        self._default_tango_host = None
        self.dft_db = None
        self.tango_db = CaselessWeakValueDict()
        self.tango_db_queries = CaselessWeakValueDict()
        self.tango_attrs = CaselessWeakValueDict()
        self.tango_devs = CaselessWeakValueDict()
        self.tango_dev_queries = CaselessWeakValueDict()
        self.tango_alias_devs = CaselessWeakValueDict()
        self.polling_timers = {}

        # Plugin device classes
        self.tango_dev_klasses = {}

        # Plugin attribute classes
        self.tango_attr_klasses = CaselessDict()

    def cleanUp(self):
        """Cleanup the singleton instance"""
        self.trace("[TangoFactory] cleanUp")
        for k, v in self.tango_attrs.items():
            v.cleanUp()
        for k, v in self.tango_dev_queries.items():
            v.cleanUp()
        for k, v in self.tango_devs.items():
            v.cleanUp()
        self.dft_db = None
        for k, v in self.tango_db_queries.items():
            v.cleanUp()
        for k, v in self.tango_db.items():
            v.cleanUp()
        self.reInit()

    def getExistingAttributes(self):
        """Returns a new dictionary will all registered attributes on this factory

           :return:  dictionary will all registered attributes on this factory
           :rtype: dict"""
        return dict(self.tango_attrs)

    def getExistingDevices(self):
        """Returns a new dictionary will all registered devices on this factory

           :return:  dictionary will all registered devices on this factory
           :rtype: dict"""
        return dict(self.tango_devs)

    def getExistingDatabases(self):
        """Returns a new dictionary will all registered databases on this factory

           :return:  dictionary will all registered databases on this factory
           :rtype: dict"""
        return dict(self.tango_db)

    def set_default_tango_host(self, tango_host):
        """Sets the new default tango host.

        :param tango_host: (str) the new tango host
        """
        self._default_tango_host = tango_host
        self.dft_db = None

    def registerAttributeClass(self, attr_name, attr_klass):
        """Registers a new attribute class for the attribute name.

           :param attr_name: (str) attribute name
           :param attr_klass: (taurus.core.tango.TangoAttribute) the new class that
                              will handle the attribute
        """
        self.tango_attr_klasses[attr_name] = attr_klass

    def unregisterAttributeClass(self, attr_name):
        """Unregisters the attribute class for the given attribute
           If no class was registered before for the given attribute, this call
           as no effect

           :param attr_name: (str) attribute name
        """
        if self.tango_attr_klasses.has_key(attr_name):
            del self.tango_attr_klasses[attr_name]

    def registerDeviceClass(self, dev_klass_name, dev_klass):
        """Registers a new python class to handle tango devices of the given tango class name

           :param dev_klass_name: (str) tango device class name
           :param dev_klass: (taurus.core.tango.TangoDevice) the new class that will
                             handle devices of the given tango class name
        """
        self.tango_dev_klasses[dev_klass_name] = dev_klass

    def unregisterDeviceClass(self, dev_klass_name):
        """Unregisters the class for the given tango class name
           If no class was registered before for the given attribute, this call
           as no effect

           :param dev_klass_name: (str) tango device class name
        """
        if self.tango_dev_klasses.has_key(dev_klass_name):
            del self.tango_dev_klasses[dev_klass_name]

    def getDatabase(self, name=None):
        '''Deprecated. Use getAuthority instead'''
        return self.getAuthority(name=name)

    def getAuthority(self, name=None):
        """
        Obtain the object corresponding to the given database name or the
        default database if name is None.
        If the corresponding authority object already exists, the existing
        instance is returned. Otherwise a new instance is stored and returned.

        :param name: (str) database name string alias. If None, the
                        default database is used

        :return: (taurus.core.tangodatabase.TangoAuthority) database object
        :raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid.
        """
        ret = None
        if name is None:
            if self.dft_db is None:
                try:
                    if self._default_tango_host is None:
                        self.dft_db = _Authority()
                    else:
                        name = self._default_tango_host
                        validator = _Authority.getNameValidator()
                        groups = validator.getUriGroups(name)
                        if groups is None:
                            raise TaurusException(
                                "Invalid default Tango authority name %s" % name)
                        self.dft_db = _Authority(host=groups['host'],
                                                 port=groups['port'])
                except:
                    self.debug("Could not create Authority", exc_info=1)
                    raise
                name = self.dft_db.getFullName()
                self.tango_db[name] = self.dft_db
            ret = self.dft_db
        else:
            ret = self.tango_db.get(name)
            if not ret is None:
                return ret
            validator = _Authority.getNameValidator()
            groups = validator.getUriGroups(name)
            if not validator.isValid(name):
                raise TaurusException("Invalid Tango authority name %s" % name)
            try:
                ret = _Authority(host=groups['host'], port=groups['port'])
            except:
                self.debug("Could not create Authority %s", groups['authority'],
                           exc_info=1)

            self.tango_db[name] = ret
        return ret

    def getDevice(self, dev_name, create_if_needed=True, **kw):
        """Obtain the object corresponding to the given tango device name.
           If the corresponding device already exists, the existing instance
           is returned. Otherwise a new instance is stored and returned.

           :param dev_name: (str) tango device name or tango alias for the
                            device. It must be a valid Tango device URI.
                            If authority is not explicit, the default Tango
                            Database will be used
           :param create_if_needed: (bool) If True, the Device is created if it
                                    did not exist previously. If False, it
                                    returns None if it did not exist

           :return: (taurus.core.tango.TangoDevice) a device object
           :raise: (taurus.core.taurusexception.TaurusException) if the given
                   dev_name is invalid.
        """
        d = self.tango_devs.get(dev_name)
        if d is None:
            d = self.tango_alias_devs.get(dev_name)
        if d is not None:
            return d

        validator = _Device.getNameValidator()
        groups = validator.getUriGroups(dev_name)
        if groups is None:
            raise TaurusException("Invalid Tango device name '%s'" % dev_name)

        full_dev_name, _, _ = validator.getNames(dev_name)

        if full_dev_name is None:
            raise TaurusException("Cannot find full name of '%s'" % dev_name)

        d = self.tango_devs.get(full_dev_name)

        if not create_if_needed:
            return d

        if d is None:
            try:
                db = self.getAuthority(groups.get('authority'))
                dev_klass = self._getDeviceClass(
                    db=db, devname=groups['devname'])
                kw['storeCallback'] = self._storeDevice
                kw['parent'] = db
                d = dev_klass(full_dev_name, **kw)
                # device objects will register themselves in this factory
                # so there is no need to do it here
            except DoubleRegistration:
                d = self.tango_devs.get(full_dev_name)
            except:
                self.debug("Error creating device %s", dev_name, exc_info=1)
                raise
        return d

    def getAttribute(self, attr_name, create_if_needed=True, **kwargs):
        """Obtain the object corresponding to the given attribute name.
           If the corresponding attribute already exists, the existing instance
           is returned. Otherwise a new instance is stored and returned.

           :param attr_name: (str) a valid attribute name URI
           :param create_if_needed: (bool) If True, the Attribute is created if
                                    it did not already exist. If False,
                                    None is returned if it did not exist
           :return: (taurus.core.tangoattribute.TangoAttribute) attribute object
           :raise: (taurus.core.taurusexception.TaurusException) if the given
                   alias is invalid.
        """
        attr = self.tango_attrs.get(attr_name)
        if attr is not None:
            return attr

        # Simple approach did not work. Lets build a proper device name
        validator = _Attribute.getNameValidator()
        groups = validator.getUriGroups(attr_name)
        if groups is None:
            raise TaurusException(("Invalid Tango attribute name '%s'") %
                                  attr_name)

        full_attr_name, _, _ = validator.getNames(attr_name)

        if full_attr_name is None:
            raise TaurusException("Cannot find full name of '%s'" % attr_name)

        attr = self.tango_attrs.get(full_attr_name)

        if attr is None:
            dev_name = full_attr_name.rsplit('/', 1)[0]
            try:
                dev = self.getDevice(dev_name)
                if dev is not None:
                    # Do another try in case the Device object created the attribute
                    # itself. This happens for the 'state' attribute
                    attr = self.tango_attrs.get(full_attr_name)
                    if attr is not None:
                        return attr
                    try:
                        attr_klass = self._getAttributeClass(
                            attr_name=attr_name)
                        kwargs['storeCallback'] = self._storeAttribute
                        if not kwargs.has_key('pollingPeriod'):
                            kwargs[
                                'pollingPeriod'] = self.getDefaultPollingPeriod()
                        attr = attr_klass(full_attr_name, dev, **kwargs)
                        # attribute objects will register themselves in this factory
                        # so there is no need to do it here
                    except DoubleRegistration:
                        attr = self.tango_attrs.get(full_attr_name)
            except:
                self.debug("Error creating attribute %s",
                           attr_name, exc_info=1)
                raise
        return attr

    def getAttributeInfo(self, full_attr_name):
        """Deprecated: Use :meth:`taurus.core.tango.TangoFactory.getConfiguration` instead.

           Obtain attribute information corresponding to the given attribute name.
           If the corresponding attribute info already exists, the existing information
           is returned. Otherwise a new information instance is stored and returned.

           :param full_attr_name: (str) attribute name in format: <tango device name>'/'<attribute name>

           :return: (taurus.core.tango.TangoConfiguration) configuration object
        """
        self.deprecated("Use getConfiguration(full_attr_name) instead")
        attr = self.getAttribute(full_attr_name)
        return attr

    @taurus4_deprecation(alt='getAttribute')
    def getConfiguration(self, param):
        """Obtain the object corresponding to the given attribute or full name.
           If the corresponding configuration already exists, the existing instance
           is returned. Otherwise a new instance is stored and returned.

           :param param: (taurus.core.taurusattribute.TaurusAttribute or str)
                         attribute object or full configuration name

           :return: (taurus.core.tango.TangoAttribute) configuration object
        """
        if isinstance(param, str):
            return self.getAttribute(param)
        return param

    def _getAttributeClass(self, **params):
        attr_name = params.get("attr_name")
        attr_klass = self.tango_attr_klasses.get(attr_name, _Attribute)
        return attr_klass

    def _getDeviceClass(self, **kwargs):
        db, dev_name = kwargs.get("db"), kwargs.get("devname")
        if db is None or dev_name is None or len(self.tango_dev_klasses) == 0:
            return _Device
        else:
            if '/' not in dev_name:  # we got an alias... find the devslashname
                dev_name = db.getElementFullName(dev_name)
            try:
                tango_dev_klass = db.get_class_for_device(dev_name)
            except PyTango.DevFailed:
                # sometimes we can't get the class (e.g. dev_name not defined)
                return _Device
            return self.tango_dev_klasses.get(tango_dev_klass, _Device)

    def _storeDevice(self, dev):
        name, alias = dev.getFullName(), dev.getSimpleName()
        exists = self.tango_devs.get(name)
        if not exists is None:
            if exists == dev:
                msg = "%s has already been registered before" % name
            else:
                msg = "%s has already been registered before with a different object!" % name
            self.debug(msg)
            raise DoubleRegistration(msg)
        self.tango_devs[name] = dev
        if not alias is None and len(alias):
            self.tango_alias_devs[alias] = dev

    def _storeAttribute(self, attr):
        name = attr.getFullName()
        exists = self.tango_attrs.get(name)
        if not exists is None:
            if exists == attr:
                msg = "%s has already been registered before" % name
            else:
                msg = "%s has already been registered before with a different object!" % name
            self.debug(msg)
            raise DoubleRegistration(msg)
        self.tango_attrs[name] = attr

    def getExistingAttribute(self, attr_name):
        """Deprecated: use getAtribute with create_if_needed=False
        """
        self.warning(('getExistingAttribute is deprecated. ' +
                      'Use getDevice with create_if_needed=False'))
        return self.getAttribute(attr_name, create_if_needed=False)

    def getExistingDevice(self, dev_name):
        """Deprecated: use getDevice with create_if_needed=False
        """
        self.warning(('getExistingDevice is deprecated. ' +
                      'Use getDevice with create_if_needed=False'))
        return self.getDevice(dev_name, create_if_needed=False)

    def removeExistingDevice(self, dev_or_dev_name):
        """Removes a previously registered device.

           :param dev_or_dev_name: (str or TangoDevice) device name or device object
        """
        if isinstance(dev_or_dev_name, _Device):
            dev = dev_or_dev_name
        else:
            dev = self.getDevice(dev_or_dev_name, create_if_needed=False)
        if dev is None:
            raise KeyError("Device %s not found" % dev_or_dev_name)
        dev.cleanUp()
        full_name = dev.getFullName()
        if self.tango_devs.has_key(full_name):
            del self.tango_devs[full_name]
        simp_name = dev.getSimpleName()
        if self.tango_alias_devs.has_key(simp_name):
            del self.tango_alias_devs[simp_name]

    def removeExistingAttribute(self, attr_or_attr_name):
        """Removes a previously registered attribute.

           :param attr_or_attr_name: (str or TangoAttribute) attribute name or attribute object
        """
        if isinstance(attr_or_attr_name, _Attribute):
            attr = attr_or_attr_name
        else:
            attr = self.getExistingAttribute(attr_or_attr_name)
        if attr is None:
            raise KeyError("Attribute %s not found" % attr_or_attr_name)
        attr.cleanUp()
        full_name = attr.getFullName()
        if self.tango_attrs.has_key(full_name):
            del self.tango_attrs[full_name]

    def isPollingEnabled(self):
        """Tells if the local tango polling is enabled

           :return: (bool) wheter or not the polling is enabled
        """
        return self._polling_enabled

    def disablePolling(self):
        """Disable the application tango polling"""
        if not self.isPollingEnabled():
            return
        self._polling_enabled = False
        for period, timer in self.polling_timers.iteritems():
            timer.stop()

    def enablePolling(self):
        """Enable the application tango polling"""
        if self.isPollingEnabled():
            return
        for period, timer in self.polling_timers.iteritems():
            timer.start()
        self._polling_enabled = True

    def getDatabaseNameValidator(self):
        """Deprecated"""
        self.warning(('getDatabaseNameValidator is deprecated.' +
                      'Use "Authority" instead of "Database"'))
        return self.getAuthorityNameValidator()

    def getAuthorityNameValidator(self):
        """Return TangoAuthorityNameValidator"""
        import tangovalidator
        return tangovalidator.TangoAuthorityNameValidator()

    def getDeviceNameValidator(self):
        """Return TangoDeviceNameValidator"""
        import tangovalidator
        return tangovalidator.TangoDeviceNameValidator()

    def getAttributeNameValidator(self):
        """Return TangoAttributeNameValidator"""
        import tangovalidator
        return tangovalidator.TangoAttributeNameValidator()

    def setOperationMode(self, mode):
        """ Deprecated. setOperationMode(OperationMode mode) -> None
            Sets the operation mode for the Tango system."""
        dep = 'setOperationMode'
        rel = 'Taurus4'
        dbg_msg = "Don't use this method"
        msg = '%s is deprecated (from %s). %s' % (dep, rel, dbg_msg)
        self.deprecated(msg)

    def getOperationMode(self):
        """Deprecated. Gives the current operation mode."""
        dep = 'getOperationMode'
        rel = 'Taurus4'
        dbg_msg = "Don't use this method"
        msg = '%s is deprecated (from %s). %s' % (dep, rel, dbg_msg)
        self.deprecated(msg)
        return OperationMode.ONLINE
Exemple #43
0
class BaseDoor(MacroServerDevice):
    """ Class encapsulating Door device functionality."""

    On = PyTango.DevState.ON
    Running = PyTango.DevState.RUNNING
    Paused = PyTango.DevState.STANDBY

    Critical = 'Critical'
    Error = 'Error'
    Warning = 'Warning'
    Info = 'Info'
    Output = 'Output'
    Debug = 'Debug'
    Result = 'Result'
    RecordData = 'RecordData'

    BlockStart = '<BLOCK>'
    BlockFinish = '</BLOCK>'

    log_streams = (Error, Warning, Info, Output, Debug, Result)

    # maximum execution time without user interruption
    InteractiveTimeout = 0.1

    def __init__(self, name, **kw):
        self._log_attr = CaselessDict()
        self._block_lines = 0
        self._in_block = False
        self._macro_server = None
        self._running_macros = None
        self._running_macro = None
        self._last_running_macro = None
        self._user_xml = None
        self._ignore_logs = kw.get("ignore_logs", False)
        self._silent = kw.get("silent", True)
        self._debug = kw.get("debug", False)
        self._output_stream = kw.get("output", sys.stdout)
        self._writeLock = threading.Lock()
        self._input_handler = self.create_input_handler()

        self.call__init__(MacroServerDevice, name, **kw)

        self._old_door_state = PyTango.DevState.UNKNOWN
        try:
            self._old_sw_door_state = TaurusSWDevState.Uninitialized
        except RuntimeError:
            # TODO: For Taurus 4 compatibility
            from taurus.core import TaurusDevState
            self._old_sw_door_state = TaurusDevState.Undefined

        self.getStateObj().addListener(self.stateChanged)

        for log_name in self.log_streams:
            tg_attr = self.getAttribute(log_name)
            attr = LogAttr(self, log_name, None, tg_attr)
            if log_name == 'Result':
                attr.subscribeEvent(self.resultReceived, log_name)
            else:
                attr.subscribeEvent(self.logReceived, log_name)
            self._log_attr[log_name] = attr

        input_attr = self.getAttribute("Input")
        input_attr.addListener(self.inputReceived)

        record_data_attr = self.getAttribute('RecordData')
        record_data_attr.addListener(self.recordDataReceived)

        macro_status_attr = self.getAttribute('MacroStatus')
        macro_status_attr.addListener(self.macroStatusReceived)

        self._experiment_configuration = ExperimentConfiguration(self)

    def create_input_handler(self):
        return BaseInputHandler()

    def get_input_handler(self):
        return self._input_handler

    def get_color_mode(self):
        return "NoColor"

    # def macrosChanged(self, s, v, t):
    #    pass

    @property
    def log_start(self):
        if not hasattr(self, "_log_start"):
            import taurus.core.util.console
            if self.get_color_mode() == "NoColor":
                kls = taurus.core.util.console.NoColors
            else:
                kls = taurus.core.util.console.TermColors
            self._log_start = {
                BaseDoor.Critical: kls.LightRed,
                BaseDoor.Error: kls.Red,
                BaseDoor.Info: kls.LightBlue,
                BaseDoor.Warning: kls.Brown,
                BaseDoor.Output: kls.Normal,
                BaseDoor.Debug: kls.DarkGray,
                BaseDoor.Result: kls.LightGreen
            }
        return self._log_start

    @property
    def log_stop(self):
        if not hasattr(self, "_log_stop"):
            import taurus.core.util.console
            if self.get_color_mode() == "NoColor":
                kls = taurus.core.util.console.NoColors
            else:
                kls = taurus.core.util.console.TermColors
            self._log_stop = {
                BaseDoor.Critical: kls.Normal,
                BaseDoor.Error: kls.Normal,
                BaseDoor.Info: kls.Normal,
                BaseDoor.Warning: kls.Normal,
                BaseDoor.Output: kls.Normal,
                BaseDoor.Debug: kls.Normal,
                BaseDoor.Result: kls.Normal
            }
        return self._log_stop

    def getStateAttr(self):
        return self._state_attr

    @property
    def macro_server(self):
        if self._macro_server is None:
            self._macro_server = self._get_macroserver_for_door()
        return self._macro_server

    def _get_macroserver_for_door(self):
        """Returns the MacroServer device object in the same DeviceServer as this
        door"""
        db = self.factory().getDatabase()
        door_name = self.dev_name()
        server_list = list(db.get_server_list('MacroServer/*'))
        server_list += list(db.get_server_list('Sardana/*'))
        server_devs = None
        for server in server_list:
            server_devs = db.get_device_class_list(server)
            devs, klasses = server_devs[0::2], server_devs[1::2]
            for dev in devs:
                if dev.lower() == door_name:
                    for i, klass in enumerate(klasses):
                        if klass == 'MacroServer':
                            return self.factory().getDevice(devs[i])
        else:
            return None

    def setDebugMode(self, state):
        self._debug = state

    def getDebugMode(self):
        return self._debug

    def setSilent(self, yesno):
        self._silent = yesno

    def isSilent(self):
        return self._silent

    def getLogObj(self, log_name='Debug'):
        return self._log_attr.get(log_name, None)

    def getRunningXML(self):
        return self._user_xml

    def getRunningMacro(self):
        return self._running_macro

    def getLastRunningMacro(self):
        return self._last_running_macro

    def abort(self, synch=True):
        if not synch:
            self.command_inout("AbortMacro")
            return

        evt_wait = AttributeEventWait(self.getAttribute("state"))
        evt_wait.lock()
        try:
            time_stamp = time.time()
            self.command_inout("AbortMacro")
            evt_wait.waitEvent(self.Running,
                               equal=False,
                               after=time_stamp,
                               timeout=self.InteractiveTimeout)
        finally:
            evt_wait.unlock()
            evt_wait.disconnect()

    def stop(self, synch=True):
        if not synch:
            self.command_inout("StopMacro")
            return

        evt_wait = AttributeEventWait(self.getAttribute("state"))
        evt_wait.lock()
        try:
            time_stamp = time.time()
            self.command_inout("StopMacro")
            evt_wait.waitEvent(self.Running,
                               equal=False,
                               after=time_stamp,
                               timeout=self.InteractiveTimeout)
        finally:
            evt_wait.unlock()
            evt_wait.disconnect()

    def _clearRunMacro(self):
        # Clear the log buffer
        map(LogAttr.clearLogBuffer, self._log_attr.values())
        self._running_macros = None
        self._running_macro = None
        self._user_xml = None
        self._block_lines = 0

    def _createMacroXml(self, macro_name, macro_params):
        """The best effort creation of the macro XML object. It tries to
        convert flat list of string parameter values to the correct macro XML
        object. The cases that can not be converted are:
            * repeat parameter containing repeat parameters
            * two repeat parameters
            * repeat parameter that is not the last parameter

        :param macro_name: (str) macro name
        :param macro_params: (sequence[str]) list of parameter values

        :return (lxml.etree._Element) macro XML element
        """
        macro_info = self.macro_server.getMacroInfoObj(macro_name)
        params_def = macro_info.parameters
        macro_node = createMacroNode(macro_name, params_def, macro_params)
        return macro_node.toXml()

    def preRunMacro(self, obj, parameters):
        self._clearRunMacro()

        xml_root = None
        if isinstance(obj, (str, unicode)):
            if obj.startswith('<') and not parameters:
                xml_root = etree.fromstring(obj)
            else:
                macros = []
                if len(parameters) == 0:
                    macros_strs = obj.split('\n')
                    for m in macros_strs:
                        pars = m.split()
                        macros.append((pars[0], pars[1:]))
                else:
                    parameters = recur_map(str, parameters)
                    macros.append((obj, parameters))
                xml_root = xml_seq = etree.Element('sequence')
                for m in macros:
                    macro_name = m[0]
                    macro_params = m[1]
                    xml_macro = self._createMacroXml(macro_name, macro_params)
                    xml_macro.set('id', str(uuid.uuid1()))
                    xml_seq.append(xml_macro)
        elif etree.iselement(obj):
            xml_root = obj
        else:
            raise TypeError('obj must be a string or a etree.Element')

        self._running_macros = {}
        for macro_xml in xml_root.xpath('//macro'):
            id, name = macro_xml.get('id'), macro_xml.get('name')
            self._running_macros[id] = Macro(self, name, id, macro_xml)
        return xml_root

    def postRunMacro(self, result, synch):
        pass

    def runMacro(self, obj, parameters=[], synch=False):
        self._user_xml = self.preRunMacro(obj, parameters)
        result = self._runMacro(self._user_xml, synch=synch)
        return self.postRunMacro(result, synch)

    def _runMacro(self, xml, synch=False):
        if not synch:
            return self.command_inout("RunMacro", [etree.tostring(xml)])
        timeout = self.InteractiveTimeout
        evt_wait = self._getEventWait()
        evt_wait.connect(self.getAttribute("state"))
        evt_wait.lock()
        try:
            evt_wait.waitEvent(self.Running, equal=False, timeout=timeout)
            ts = time.time()
            result = self.command_inout("RunMacro", [etree.tostring(xml)])
            evt_wait.waitEvent(self.Running, after=ts, timeout=timeout)
            if synch:
                evt_wait.waitEvent(self.Running,
                                   equal=False,
                                   after=ts,
                                   timeout=timeout)
        finally:
            self._clearRunMacro()
            evt_wait.unlock()
            evt_wait.disconnect()
        return result

    def stateChanged(self, s, t, v):
        self._old_door_state = self.getState()
        try:
            self._old_sw_door_state = self.getSWState()
        except:
            # TODO: For Taurus 4 compatibility
            self._old_sw_door_state = self.state

    def resultReceived(self, log_name, result):
        """Method invoked by the arrival of a change event on the Result attribute"""
        if self._ignore_logs or self._running_macro is None:
            return
        self._running_macro.setResult(result)
        return result

    def putEnvironment(self, name, value):
        self.macro_server.putEnvironment(name, value)

    def putEnvironments(self, obj):
        self.macro_server.putEnvironments(obj)

    setEnvironment = putEnvironment
    setEnvironments = putEnvironments

    def getEnvironment(self, name=None):
        return self.macro_server.getEnvironment(name=name)

    def inputReceived(self, s, t, v):
        if t not in CHANGE_EVT_TYPES:
            return
        if v is None or self._running_macros is None:
            return
        input_data = CodecFactory().decode(('json', v.value))
        self.processInput(input_data)

    def processInput(self, input_data):
        TaurusManager().addJob(self._processInput, None, input_data)

    def _processInput(self, input_data):
        input_type = input_data['type']
        if input_type == 'input':
            result = self._input_handler.input(input_data)
            if result['input'] is '' and 'default_value' in input_data:
                result['input'] = input_data['default_value']
            result = CodecFactory().encode('json', ('', result))[1]
            self.write_attribute('Input', result)
        elif input_type == 'timeout':
            self._input_handler.input_timeout(input_data)

    def recordDataReceived(self, s, t, v):
        if t not in CHANGE_EVT_TYPES:
            return
        return self._processRecordData(v)

    def _processRecordData(self, data):
        if data is None or data.value is None:
            return
        # make sure we get it as string since PyTango 7.1.4 returns a buffer
        # object and json.loads doesn't support buffer objects (only str)
        data = map(str, data.value)

        size = len(data[1])
        if size == 0:
            return
        format = data[0]
        codec = CodecFactory().getCodec(format)
        data = codec.decode(data)
        return data

    def processRecordData(self, data):
        pass

    def macroStatusReceived(self, s, t, v):
        if v is None or self._running_macros is None:
            return
        if t not in CHANGE_EVT_TYPES:
            return

        # make sure we get it as string since PyTango 7.1.4 returns a buffer
        # object and json.loads doesn't support buffer objects (only str)
        v = map(str, v.value)
        if not len(v[1]):
            return
        format = v[0]
        codec = CodecFactory().getCodec(format)

        # make sure we get it as string since PyTango 7.1.4 returns a buffer
        # object and json.loads doesn't support buffer objects (only str)
        v[1] = str(v[1])
        fmt, data = codec.decode(v)
        for macro_status in data:
            id = macro_status.get('id')
            macro = self._running_macros.get(id)
            self._last_running_macro = self._running_macro = macro
            # if we don't have the ID it's because the macro is running a submacro
            # or another client is connected to the same door (shame on him!) and
            # executing a macro we discard this event
            if macro is not None:
                macro.__dict__.update(macro_status)
        return data

    def logReceived(self, log_name, output):
        if not output or self._silent or self._ignore_logs:
            return

        if log_name == self.Debug and not self._debug:
            return

        o = self.log_start[log_name]
        for line in output:
            if not self._debug:
                if line == self.BlockStart:
                    self._in_block = True
                    for i in xrange(self._block_lines):
                        # erase current line, up one line, erase current line
                        o += '\x1b[2K\x1b[1A\x1b[2K'
                    self._block_lines = 0
                    continue
                elif line == self.BlockFinish:
                    self._in_block = False
                    continue
                else:
                    if self._in_block:
                        self._block_lines += 1
                    else:
                        self._block_lines = 0
            o += "%s\n" % line

        o += self.log_stop[log_name]
        self.write(o)

    def write(self, msg, stream=None):
        if self.isSilent():
            return
        msg = msg.encode('utf-8')
        self._output_stream = sys.stdout
        out = self._output_stream
        if not stream is None:
            start, stop = self.log_start.get(stream), self.log_stop.get(stream)
            if start is not None and stop is not None:
                out.write(start)
                out.write(msg)
                out.write(stop)
                out.flush()
                return
        out.write(msg)
        out.flush()

    def writeln(self, msg='', stream=None):
        self.write("%s\n" % msg, stream=stream)

    def getExperimentConfigurationObj(self):
        return self._experiment_configuration

    def getExperimentConfiguration(self):
        return self._experiment_configuration.get()

    def setExperimentConfiguration(self, config, mnt_grps=None):
        self._experiment_configuration.set(config, mnt_grps=mnt_grps)
Exemple #44
0
    3: Qt.Qt.BDiagPattern,
    4: Qt.Qt.DiagCrossPattern,
    5: Qt.Qt.FDiagPattern,
    6: Qt.Qt.BDiagPattern,
    7: Qt.Qt.Dense5Pattern,
    8: Qt.Qt.Dense7Pattern,
    9: Qt.Qt.Dense6Pattern,
    10: Qt.Qt.Dense4Pattern,
    11: Qt.Qt.LinearGradientPattern
}

TEXTHINT_JDW2QT = CaselessDict({
    'helvetica': Qt.QFont.Helvetica,
    'serif': Qt.QFont.Serif,
    'sansserif': Qt.QFont.SansSerif,
    'courier': Qt.QFont.Courier,
    'Monospaced': Qt.QFont.Courier,
    'times': Qt.QFont.Times,
    '': Qt.QFont.AnyStyle,
})

ALIGNMENT = {
    0: Qt.Qt.AlignHCenter,
    1: Qt.Qt.AlignLeft,
    2: Qt.Qt.AlignRight,
}

VALIGNMENT = {
    0: Qt.Qt.AlignVCenter,
    1: Qt.Qt.AlignTop,
    2: Qt.Qt.AlignBottom,
Exemple #45
0
class MacroServer(MSContainer, MSObject, SardanaElementManager, SardanaIDManager):

    All = "All"

    MaxParalellMacros = 5

    logReportParams = dict(when='midnight', interval=1, backupCount=365)
    logReportKlass = NonOverlappingTimedRotatingFileHandler

    def __init__(self, full_name, name=None, macro_path=None,
                 environment_db=None, recorder_path=None):
        # dict<str, Pool>
        # key   - device name (case insensitive)
        # value - Pool object representing the device name
        self._pools = CaselessDict()
        self._max_parallel_macros = self.MaxParalellMacros
        self._path_id = None

        MSContainer.__init__(self)
        MSObject.__init__(self, full_name=full_name, name=name, id=InvalidId,
                          macro_server=self, elem_type=ElementType.MacroServer)

        registerExtensions()

        self._type_manager = TypeManager(self)
        self._environment_manager = EnvironmentManager(self,
                                                       environment_db=environment_db)
        self._macro_manager = MacroManager(self, macro_path=macro_path)
        self._recorder_manager = RecorderManager(self,
                                                 recorder_path=recorder_path)

    def serialize(self, *args, **kwargs):
        kwargs = MSObject.serialize(self, *args, **kwargs)
        kwargs['type'] = self.__class__.__name__
        kwargs['id'] = InvalidId
        kwargs['parent'] = None
        return kwargs

    def add_job(self, job, callback=None, *args, **kw):
        th_pool = get_thread_pool()
        th_pool.add(job, callback, *args, **kw)

    # --------------------------------------------------------------------------
    # Environment DB related methods
    # --------------------------------------------------------------------------

    def set_environment_db(self, environment_db):
        """Sets the environment database.

        :param env_db:
            environment database name
        :type env_db: :obj:`str`
        """
        self.environment_manager.setEnvironmentDb(environment_db)

    # --------------------------------------------------------------------------
    # Python related methods
    # --------------------------------------------------------------------------

    def set_python_path(self, path):
        mod_man = ModuleManager()
        if self._path_id is not None:
            mod_man.remove_python_path(self._path_id)
        self._path_id = mod_man.add_python_path(path)

    # --------------------------------------------------------------------------
    # Macro path related methods
    # --------------------------------------------------------------------------

    def set_macro_path(self, macro_path):
        """Sets the macro path.

        :param macro_path:
            macro path
        :type macro_path:
            seq<str>
        """
        self.macro_manager.setMacroPath([p.rstrip(os.sep) for p in macro_path])

    # --------------------------------------------------------------------------
    # Recorder path related methods
    # --------------------------------------------------------------------------

    def set_recorder_path(self, recorder_path):
        """Sets the recorder path.

        :param recorder_path:
            recorder path
        :type recorder_path:
            seq<str>
        """
        self.recorder_manager.setRecorderPath(recorder_path)

    # --------------------------------------------------------------------------
    # Report related methods
    # --------------------------------------------------------------------------

    def set_log_report(self, filename=None, format=None):
        log = self.get_report_logger()

        # first check that the handler has not been initialized yet. If it has
        # we remove previous handlers. We only allow one timed rotating file
        # handler at a time
        to_remove = []
        for handler in log.handlers:
            if isinstance(handler, logging.handlers.TimedRotatingFileHandler):
                to_remove.append(handler)

        for handler in to_remove:
            handler.close()
            log.removeHandler(handler)

        if filename is None:
            return

        if format is None:
            format = Logger.DftLogMessageFormat
        formatter = logging.Formatter(format)

        self.info("Reports are being stored in %s", filename)
        klass = self.logReportKlass
        handler = klass(filename, **self.logReportParams)
        handler.setFormatter(formatter)
        log.addHandler(handler)

    def clear_log_report(self):
        self.set_log_report()

    def get_report_logger(self):
        return logging.getLogger("Sardana.Report")

    report_logger = property(get_report_logger)

    def report(self, msg, *args, **kwargs):
        """
        Record a log message in the sardana report (if enabled) with default
        level **INFO**. The msg is the message format string, and the args are
        the arguments which are merged into msg using the string formatting
        operator. (Note that this means that you can use keywords in the
        format string, together with a single dictionary argument.)

        *kwargs* are the same as :meth:`logging.Logger.debug` plus an optional
        level kwargs which has default value **INFO**

        Example::

            self.report("this is an official report!")

        :param msg: the message to be recorded
        :type msg: :obj:`str`
        :param args: list of arguments
        :param kwargs: list of keyword arguments"""
        level = kwargs.pop('level', logging.INFO)
        return self.report_logger.log(level, msg, *args, **kwargs)

    # --------------------------------------------------------------------------
    # Pool related methods
    # --------------------------------------------------------------------------

    def set_pool_names(self, pool_names):
        """Registers a new list of device pools in this manager

        :param pool_names: sequence of pool names
        :type pool_names: seq<str>"""
        for pool in self._pools.values():
            elements_attr = pool.getAttribute("Elements")
            elements_attr.removeListener(self.on_pool_elements_changed)

        for name in pool_names:
            self.debug("Creating pool %s", name)
            pool = Device(name)
            if pool is None:
                self.error('Could not create Pool object for %s' % name)
                continue
            self._pools[name] = pool
            elements_attr = pool.getAttribute("Elements")
            elements_attr.addListener(self.on_pool_elements_changed)

    def get_pool_names(self):
        """Returns the list of names of the pools this macro server is connected
        to.

        :return:
            the list of names of the pools this macro server is connected to
        :rtype:
            seq<str>"""
        return self._pools.keys()

    def get_pool(self, pool_name):
        """Returns the device pool object corresponding to the given device name
        or None if no match is found.

        :param pool_name: device pool name
        :type pool_name: :obj:`str`
        :return: Pool object or None if no match is found"""
        return self._pools.get(pool_name)

    def get_pools(self):
        """Returns the list of pools this macro server is connected to.

        :return: the list of pools this macro server is connected to
        :rtype: seq<Pool>"""
        return self._pools.values()

    def on_pool_elements_changed(self, evt_src, evt_type, evt_value):
        if evt_type not in CHANGE_EVT_TYPES:
            return
        self.fire_event(EventType("PoolElementsChanged"), evt_value)

    # --------------------------------------------------------------------------
    # Door related methods
    # --------------------------------------------------------------------------

    def create_element(self, **kwargs):
        type = kwargs['type']
        elem_type = ElementType[type]
        name = kwargs['name']

        kwargs['macro_server'] = self

        td = TYPE_MAP_OBJ[elem_type]
        klass = td.klass
        auto_full_name = td.auto_full_name

        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))

        self.check_element(name, full_name)

        id = kwargs.get('id')
        if id is None:
            kwargs['id'] = id = self.get_new_id()
        else:
            self.reserve_id(id)
        elem = klass(**kwargs)
        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret

    def create_door(self, **kwargs):
        return self.create_element(type="Door", **kwargs)

    # --------------------------------------------------------------------------
    # General access to elements
    # --------------------------------------------------------------------------

    def get_elements_info(self):
        return self.get_remote_elements_info() + self.get_local_elements_info()

    def get_remote_elements_info(self):
        return [elem.serialize()
                for pool in self.get_pools()
                for elem in pool.getElements()]

    def get_local_elements_info(self):
        # fill macro library info
        ret = [macrolib.serialize()
               for macrolib in self.get_macro_libs().values()]
        # fill macro info
        ret += [macro.serialize()
                for macro in self.get_macros().values()]
        # fill parameter type info
        ret += [paramtype.serialize()
                for paramtype in self.get_data_types().values()]

        return ret

    # --------------------------------------------------------------------------
    # macro execution
    # --------------------------------------------------------------------------

    def set_max_parallel_macros(self, nb):
        assert nb > 0, "max parallel macros number must be > 0"
        th_pool = get_thread_pool()
        if th_pool.size + 5 < nb:
            th_pool.size = nb
        self._max_parallel_macros = nb

    def get_max_parallel_macros(self):
        return self._max_parallel_macros

    max_parallel_macros = property(get_max_parallel_macros,
                                   set_max_parallel_macros, doc="maximum number of macros which can "
                                   "execute at the same time")

    @property
    def macro_manager(self):
        return self._macro_manager

    @property
    def recorder_manager(self):
        return self._recorder_manager

    @property
    def environment_manager(self):
        return self._environment_manager

    @property
    def type_manager(self):
        return self._type_manager

    # --------------------------------------------------------------------------
    # (Re)load code
    # --------------------------------------------------------------------------

    def reload_lib(self, lib_name):
        return self.macro_manager.reloadLib(lib_name)

    def reload_macro_lib(self, lib_name):
        manager = self.macro_manager

        try:
            old_lib = manager.getMacroLib(lib_name)
        except UnknownMacroLibrary:
            old_lib = None

        new_elements, changed_elements, deleted_elements = [], [], []

        new_lib = manager.reloadMacroLib(lib_name)
        if new_lib.has_errors():
            return new_lib

        if old_lib is None:
            new_elements.extend(new_lib.get_macros())
            new_elements.append(new_lib)
        else:
            changed_elements.append(new_lib)
            new_names = set([macro.name for macro in new_lib.get_macros()])
            old_names = set([macro.name for macro in old_lib.get_macros()])
            changed_names = set.intersection(new_names, old_names)
            deleted_names = old_names.difference(new_names)
            new_names = new_names.difference(old_names)

            for new_name in new_names:
                new_elements.append(new_lib.get_macro(new_name))
            for changed_name in changed_names:
                changed_elements.append(new_lib.get_macro(changed_name))
            for deleted_name in deleted_names:
                deleted_elements.append(old_lib.get_macro(deleted_name))

        evt = {"new": new_elements, "change": changed_elements,
               "del": deleted_elements}
        self.fire_event(EventType("ElementsChanged"), evt)
        return new_lib

    reload_macro_lib.__doc__ = MacroManager.reloadMacroLib.__doc__

    def reload_macro_libs(self, lib_names):
        for lib_name in lib_names:
            self.reload_macro_lib(lib_name)

    def reload_macro(self, macro_name):
        macro_info = self.macro_manager.getMacro(macro_name)
        lib_name = macro_info.module_name
        return self.reload_macro_lib(lib_name)

    def reload_macros(self, macro_names):
        lib_names = set()
        for macro_name in macro_names:
            macro_info = self.macro_manager.getMacro(macro_name)
            lib_names.add(macro_info.module_name)
        self.reload_macro_libs(lib_names)

    def get_macro_lib(self, lib_name):
        return self.macro_manager.getMacroLib(lib_name)
    get_macro_lib.__doc__ = MacroManager.getMacroLib.__doc__

    def get_macro_libs(self, filter=None):
        return self.macro_manager.getMacroLibs(filter=filter)
    get_macro_libs.__doc__ = MacroManager.getMacroLibs.__doc__

    def get_macro_lib_names(self):
        return self.macro_manager.getMacroLibNames()
    get_macro_lib_names.__doc__ = MacroManager.getMacroLibNames.__doc__

    def get_macro(self, name):
        return self.macro_manager.getMacro(name)
    get_macro.__doc__ = MacroManager.getMacro.__doc__

    def get_macros(self, filter=None):
        return self.macro_manager.getMacros(filter=filter)
    get_macros.__doc__ = MacroManager.getMacros.__doc__

    def get_macro_names(self):
        return self.macro_manager.getMacroNames()
    get_macro_names.__doc__ = MacroManager.getMacroNames.__doc__

    def get_macro_classes(self):
        return self.macro_manager.getMacroClasses()
    get_macro_classes.__doc__ = MacroManager.getMacroClasses.__doc__

    def get_macro_functions(self):
        return self.macro_manager.getMacroFunctions()
    get_macro_functions.__doc__ = MacroManager.getMacroFunctions.__doc__

    def get_macro_libs_summary_info(self):
        libs = self.get_macro_libs()
        ret = []
        for module_name, macro_lib_info in libs.items():
            elem = "%s (%s)" % (macro_lib_info.name, macro_lib_info.file_path)
            ret.append(elem)
        return ret

    def get_macro_classes_summary_info(self):
        macros = self.get_macros()
        ret = []
        for macro_info in macros:
            elem = "%s (%s)" % (macro_info.name, macro_info.file_path)
            ret.append(elem)
        return ret

    def get_or_create_macro_lib(self, lib_name, macro_name=None):
        """Gets the exiting macro lib or creates a new macro lib file. If
        name is not None, a macro template code for the given macro name is
        appended to the end of the file.

        :param lib_name:
            module name, python file name, or full file name (with path)
        :type lib_name: :obj:`str`
        :param macro_name:
            an optional macro name. If given a macro template code is appended
            to the end of the file (default is None meaning no macro code is
            added)
        :type macro_name: :obj:`str`

        :return:
            a sequence with three items: full_filename, code, line number is 0
            if no macro is created or n representing the first line of code for
            the given macro name.
        :rtype: seq<str, str, int>"""
        return self.macro_manager.getOrCreateMacroLib(lib_name,
                                                      macro_name=macro_name)
    get_or_create_macro_lib.__doc__ = MacroManager.getOrCreateMacroLib.__doc__

    def set_macro_lib(self, lib_name, code, auto_reload=True):
        module_name = self.macro_manager.setMacroLib(lib_name, code,
                                                     auto_reload=False)
        if auto_reload:
            self.reload_macro_lib(module_name)

    set_macro_lib.__doc__ = MacroManager.setMacroLib.__doc__

    # --------------------------------------------------------------------------
    # Data types
    # --------------------------------------------------------------------------

    def get_data_types(self):
        return self.type_manager.getTypes()
    get_data_types.__doc__ = TypeManager.getTypes.__doc__

    def get_data_type(self, type_name):
        return self.type_manager.getTypeObj(type_name)
    get_data_type.__doc__ = TypeManager.getTypeObj.__doc__

    def get_data_type_names(self):
        return self.type_manager.getTypeNames()
    get_data_type_names.__doc__ = TypeManager.getTypeNames.__doc__

    def get_data_type_names_with_asterisc(self):
        return self.type_manager.getTypeListStr()
    get_data_type_names_with_asterisc.__doc__ = TypeManager.getTypeListStr.__doc__

    # --------------------------------------------------------------------------
    # Doors
    # --------------------------------------------------------------------------

    def get_doors(self):
        return self.get_elements_by_type(ElementType.Door)

    def get_door_names(self):
        return [door.full_name for door in self.get_doors()]

    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
    # Environment access methods
    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-

    def get_env(self, key=None, door_name=None, macro_name=None):
        """Gets the environment matching the given parameters:

               - door_name and macro_name define the context where to look for
                 the environment. If both are None, the global environment is
                 used. If door name is None but macro name not, the given macro
                 environment is used and so on...
               - If key is None it returns the complete environment, otherwise
                 key must be a string containing the environment variable name.

        :param key:
            environment variable name [default: None, meaning all environment]
        :type key: :obj:`str`
        :param door_name:
            local context for a given door [default: None, meaning no door
            context is used]
        :type door_name: :obj:`str`
        :param macro_name:
            local context for a given macro [default: None, meaning no macro
            context is used]
        :type macro_name: :obj:`str`

        :return: a :obj:`dict` containing the environment
        :rtype: :obj:`dict`

        :raises: UnknownEnv"""
        return self.environment_manager.getEnv(key=key, macro_name=macro_name,
                                               door_name=door_name)

    def set_env(self, key, value):
        """Sets the environment key to the new value and stores it persistently.

        :param key: the key for the environment
        :param value: the value for the environment

        :return: a tuple with the key and value objects stored"""
        env_man = self.environment_manager
        if env_man.hasEnv(key):
            evt_type = "change"
        else:
            evt_type = "new"

        k, v = self.environment_manager.setEnv(key, value)

        evt = {evt_type: {k: v}}
        self.fire_event(EventType("EnvironmentChanged"), evt)
        return k, v

    def set_env_obj(self, data):
        """Sets the environment key to the new value and stores it persistently.

        :param key: the key for the environment
        :param value: the value for the environment

        :return: a tuple with the key and value objects stored"""
        env_man = self.environment_manager

        new, change = {}, {}
        for key, value in data.items():
            d = new
            if env_man.hasEnv(key):
                d = change
            d[key] = value

        ret = env_man.setEnvObj(data)

        evt = dict(new=new, change=change)
        self.fire_event(EventType("EnvironmentChanged"), evt)
        return ret

    def change_env(self, data):
        env_man = self.environment_manager
        new_change_env = data.get('new', {})
        new_change_env.update(data.get('change', {}))
        del_env = data.get('del', [])

        new, change = {}, {}
        for key, value in new_change_env.items():
            d = new
            if env_man.hasEnv(key):
                d = change
            d[key] = value

        del_keys = env_man.unsetEnv(del_env)
        env_man.setEnvObj(new_change_env)

        evt = dict(new=new, change=change)
        evt['del'] = del_keys
        self.fire_event(EventType("EnvironmentChanged"), evt)

    def unset_env(self, key):
        """Unsets the environment for the given key.

        :param key: the key for the environment to be unset"""
        ret = self.environment_manager.unsetEnv(key)
        # list is unhashable - convert to a tuple
        if isinstance(key, list):
            key = tuple(key)
        evt = {'del': {key: None}}
        self.fire_event(EventType("EnvironmentChanged"), evt)
        return ret

    def has_env(self, key, macro_name=None, door_name=None):
        return self.environment_manager.hasEnv(key,
                                               macro_name=macro_name, door_name=door_name)

    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
    # General object access methods
    #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-

    def get_object(self, name, type_class=All, subtype=All, pool=All):
        objs = self.find_objects(name, type_class, subtype, pool)
        if len(objs) == 0:
            return None
        if len(objs) > 1:
            raise AttributeError(
                'More than one object named "%s" found' % name)
        return objs[0]

    def get_objects(self, names, type_class=All, subtype=All, pool=All):
        return self.find_objects(names, type_class=type_class, subtype=subtype,
                                 pool=pool)

    def find_objects(self, param, type_class=All, subtype=All, pool=All):
        if is_pure_str(param):
            param = param,

        if type_class == MacroServer.All:
            type_name_list = self.get_data_type_names()
        else:
            if is_pure_str(type_class):
                type_name_list = type_class,
            else:
                type_name_list = type_class
        obj_set = set()
        param = ['^%s$' % x for x in param]
        re_objs = map(re.compile, param, len(param) * (re.IGNORECASE,))
        re_subtype = re.compile(subtype, re.IGNORECASE)
        for type_name in type_name_list:
            type_class_name = type_name
            if type_class_name.endswith('*'):
                type_class_name = type_class_name[:-1]
            type_inst = self.get_data_type(type_class_name)
            if not type_inst.hasCapability(ParamType.ItemList):
                continue
            if self.is_macroserver_interface(type_class_name):
                for name, obj in type_inst.getObjDict(pool=pool).items():
                    for re_obj in re_objs:
                        if re_obj.match(name) is not None:
                            obj_type = ElementType[obj.get_type()]
                            if subtype is MacroServer.All or re_subtype.match(obj_type):
                                obj_set.add(obj)
            else:
                for name, obj in type_inst.getObjDict(pool=pool).items():
                    for re_obj in re_objs:
                        if re_obj.match(name) is not None:
                            obj_type = obj.getType()
                            if (subtype is MacroServer.All or
                                re_subtype.match(obj.getType())) and \
                               obj_type != "MotorGroup":
                                obj_set.add(obj)
        return list(obj_set)

    def get_motion(self, elems, motion_source=None, read_only=False, cache=True,
                   decoupled=False):
        if motion_source is None:
            motion_source = self.get_pools()

        motion_klass = Motion
        if decoupled:  # and len(elems)>1:
            motion_klass = MotionGroup
        return motion_klass(elems, motion_source)

    _LOCAL_INTERFACES = {
        Interface.MacroLibrary: get_macro_libs,
        Interface.MacroCode: get_macros,
        Interface.MacroClass: get_macro_classes,
        Interface.MacroFunction: get_macro_functions,
    }

    def is_macroserver_interface(self, interface):
        if is_pure_str(interface):
            interface = Interface[interface]
        return interface in self._LOCAL_INTERFACES

    def get_elements_with_interface(self, interface):
        ret = CaselessDict()
        if is_pure_str(interface):
            interface_str = interface
            interface = Interface[interface_str]
        else:
            interface_str = Interface[interface]

        if self.is_macroserver_interface(interface):
            ret.update(self._LOCAL_INTERFACES.get(interface)(self))
        else:
            for pool in self.get_pools():
                ret.update(pool.getElementsWithInterface(interface_str))
        return ret

    def get_element_with_interface(self, name, interface):
        for pool in self.get_pools():
            element = pool.getElementWithInterface(name, interface)
            if element is not None:
                return element

    def get_controllers(self):
        return self.get_elements_with_interface("Controller")

    def get_moveables(self):
        return self.get_elements_with_interface("Moveable")

    def get_motors(self):
        return self.get_elements_with_interface("Motor")

    def get_pseudo_motors(self):
        return self.get_elements_with_interface("PseudoMotor")

    def get_io_registers(self):
        return self.get_elements_with_interface("IORegister")

    def get_measurement_groups(self):
        return self.get_elements_with_interface("MeasurementGroup")

    def get_exp_channels(self):
        return self.get_elements_with_interface("ExpChannel")

    def get_counter_timers(self):
        return self.get_elements_with_interface("CTExpChannel")

    def get_0d_exp_channels(self):
        return self.get_elements_with_interface("ZeroDExpChannel")

    def get_1d_exp_channels(self):
        return self.get_elements_with_interface("OneDExpChannel")

    def get_2d_exp_channels(self):
        return self.get_elements_with_interface("TwoDExpChannel")

    def get_pseudo_counters(self):
        return self.get_elements_with_interface("PseudoCounter")

    def get_instruments(self):
        return self.get_elements_with_interface("Instrument")

    def get_controller(self, name):
        return self.get_element_with_interface(name, "Controller")

    def get_moveable(self, name):
        return self.get_element_with_interface(name, "Moveable")

    def get_motor(self, name):
        return self.get_element_with_interface(name, "Motor")

    def get_pseudo_motor(self, name):
        return self.get_element_with_interface(name, "PseudoMotor")

    def get_io_register(self, name):
        return self.get_element_with_interface(name, "IORegister")

    def get_measurement_group(self, name):
        return self.get_element_with_interface(name, "MeasurementGroup")

    def get_exp_channel(self, name):
        return self.get_element_with_interface(name, "ExpChannel")

    def get_counter_timer(self, name):
        return self.get_element_with_interface(name, "CTExpChannel")

    def get_0d_exp_channel(self, name):
        return self.get_element_with_interface(name, "ZeroDExpChannel")

    def get_1d_exp_channel(self, name):
        return self.get_element_with_interface(name, "OneDExpChannel")

    def get_2d_exp_channel(self, name):
        return self.get_element_with_interface(name, "TwoDExpChannel")

    def get_pseudo_counter(self, name):
        return self.get_element_with_interface(name, "PseudoCounter")

    def get_instrument(self, name):
        return self.get_element_with_interface(name, "Instrument")
    def __init__(self,
                 parent=None,
                 curvePropDict={},
                 showButtons=False,
                 autoApply=False,
                 designMode=False):
        # try:
        super(CurvesAppearanceChooser, self).__init__(parent)
        self.loadUi()
        self.autoApply = autoApply
        self.sStyleCB.insertItems(0, sorted(NamedSymbolStyles.values()))
        self.lStyleCB.insertItems(0, NamedLineStyles.values())
        self.cStyleCB.insertItems(0, NamedCurveStyles.values())
        self.sColorCB.addItem("")
        self.lColorCB.addItem("")
        if not showButtons:
            self.applyBT.hide()
            self.resetBT.hide()
        for color in NamedColors:
            icon = self._colorIcon(color)
            self.sColorCB.addItem(icon, "", Qt.QVariant(Qt.QColor(color)))
            self.lColorCB.addItem(icon, "", Qt.QVariant(Qt.QColor(color)))
        self.__itemsDict = CaselessDict()
        self.setCurves(curvePropDict)
        # set the icon for the background button (stupid designer limitations
        # forces to do it programatically)
        self.bckgndBT.setIcon(getIcon(":/color-fill.svg"))

        # connections.
        # Note: The assignToY1BT and assignToY2BT buttons are not connected to anything
        # Their signals are handled by the Config dialog because we haven't got
        # access to the curve objects here
        Qt.QObject.connect(self.curvesLW, Qt.SIGNAL("itemSelectionChanged()"),
                           self.onSelectedCurveChanged)
        Qt.QObject.connect(self.curvesLW,
                           Qt.SIGNAL("itemChanged(QListWidgetItem *)"),
                           self.onItemChanged)
        Qt.QObject.connect(self.applyBT, Qt.SIGNAL("clicked()"), self.onApply)
        Qt.QObject.connect(self.resetBT, Qt.SIGNAL("clicked()"), self.onReset)
        Qt.QObject.connect(self.sStyleCB,
                           Qt.SIGNAL("currentIndexChanged(const QString&)"),
                           self._onSymbolStyleChanged)

        Qt.QObject.connect(self.sStyleCB,
                           Qt.SIGNAL("currentIndexChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.lStyleCB,
                           Qt.SIGNAL("currentIndexChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.sColorCB,
                           Qt.SIGNAL("currentIndexChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.lColorCB,
                           Qt.SIGNAL("currentIndexChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.cStyleCB,
                           Qt.SIGNAL("currentIndexChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.sSizeSB, Qt.SIGNAL("valueChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.lWidthSB, Qt.SIGNAL("valueChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.sFillCB, Qt.SIGNAL("stateChanged(int)"),
                           self.onControlChanged)
        Qt.QObject.connect(self.cFillCB, Qt.SIGNAL("stateChanged(int)"),
                           self.onControlChanged)
Exemple #47
0
class BaseDoor(MacroServerDevice):
    """ Class encapsulating Door device functionality."""

    On = PyTango.DevState.ON
    Running = PyTango.DevState.RUNNING
    Paused = PyTango.DevState.STANDBY

    Critical = 'Critical'
    Error = 'Error'
    Warning = 'Warning'
    Info = 'Info'
    Output = 'Output'
    Debug = 'Debug'
    Result = 'Result'
    RecordData = 'RecordData'

    BlockStart = '<BLOCK>'
    BlockFinish = '</BLOCK>'

    log_streams = (Error, Warning, Info, Output, Debug, Result)

    # maximum execution time without user interruption
    InteractiveTimeout = 0.1


    def __init__(self, name, **kw):
        self._log_attr = CaselessDict()
        self._block_lines = 0
        self._in_block = False
        self._macro_server = None
        self._running_macros = None
        self._running_macro = None
        self._last_running_macro = None
        self._user_xml = None
        self._ignore_logs = kw.get("ignore_logs", False)
        self._silent = kw.get("silent", True)
        self._debug = kw.get("debug", False)
        self._output_stream = kw.get("output", sys.stdout)
        self._writeLock = threading.Lock()
        self._input_handler = self.create_input_handler()

        self.call__init__(MacroServerDevice, name, **kw)

        self._old_door_state = PyTango.DevState.UNKNOWN
        try:
            self._old_sw_door_state = TaurusSWDevState.Uninitialized
        except RuntimeError:
            #TODO: For Taurus 4 compatibility
            from taurus.core import TaurusDevState
            self._old_sw_door_state = TaurusDevState.Undefined 

        self.getStateObj().addListener(self.stateChanged)

        for log_name in self.log_streams:
            tg_attr = self.getAttribute(log_name)
            attr = LogAttr(self, log_name, None, tg_attr)
            if log_name == 'Result':
                attr.subscribeEvent(self.resultReceived, log_name)
            else:
                attr.subscribeEvent(self.logReceived, log_name)
            self._log_attr[log_name] = attr

        input_attr = self.getAttribute("Input")
        input_attr.addListener(self.inputReceived)

        record_data_attr = self.getAttribute('RecordData')
        record_data_attr.addListener(self.recordDataReceived)

        macro_status_attr = self.getAttribute('MacroStatus')
        macro_status_attr.addListener(self.macroStatusReceived)

        self._experiment_configuration = ExperimentConfiguration(self)

    def create_input_handler(self):
        return BaseInputHandler()

    def get_input_handler(self):
        return self._input_handler

    def get_color_mode(self):
        return "NoColor"

    #def macrosChanged(self, s, v, t):
    #    pass

    @property
    def log_start(self):
        if not hasattr(self, "_log_start"):
            import taurus.core.util.console
            if self.get_color_mode() == "NoColor":
                kls = taurus.core.util.console.NoColors
            else:
                kls = taurus.core.util.console.TermColors
            self._log_start = { BaseDoor.Critical : kls.LightRed,
                                BaseDoor.Error    : kls.Red,
                                BaseDoor.Info     : kls.LightBlue,
                                BaseDoor.Warning  : kls.Brown,
                                BaseDoor.Output   : kls.Normal,
                                BaseDoor.Debug    : kls.DarkGray,
                                BaseDoor.Result   : kls.LightGreen }
        return self._log_start

    @property
    def log_stop(self):
        if not hasattr(self, "_log_stop"):
            import taurus.core.util.console
            if self.get_color_mode() == "NoColor":
                kls = taurus.core.util.console.NoColors
            else:
                kls = taurus.core.util.console.TermColors
            self._log_stop = {  BaseDoor.Critical : kls.Normal,
                                BaseDoor.Error    : kls.Normal,
                                BaseDoor.Info     : kls.Normal,
                                BaseDoor.Warning  : kls.Normal,
                                BaseDoor.Output   : kls.Normal,
                                BaseDoor.Debug    : kls.Normal,
                                BaseDoor.Result   : kls.Normal }
        return self._log_stop

    def getStateAttr(self):
        return self._state_attr

    @property
    def macro_server(self):
        if self._macro_server is None:
            self._macro_server = self._get_macroserver_for_door()
        return self._macro_server

    def _get_macroserver_for_door(self):
        """Returns the MacroServer device object in the same DeviceServer as this
        door"""
        db = self.factory().getDatabase()
        door_name = self.dev_name()
        server_list = list(db.get_server_list('MacroServer/*'))
        server_list += list(db.get_server_list('Sardana/*'))
        server_devs = None
        for server in server_list:
            server_devs = db.get_device_class_list(server)
            devs, klasses = server_devs[0::2], server_devs[1::2]
            for dev in devs:
                if dev.lower() == door_name:
                    for i, klass in enumerate(klasses):
                        if klass == 'MacroServer':
                            return self.factory().getDevice(devs[i])
        else:
            return None

    def setDebugMode(self, state):
        self._debug = state

    def getDebugMode(self):
        return self._debug

    def setSilent(self, yesno):
        self._silent = yesno

    def isSilent(self):
        return self._silent

    def getLogObj(self, log_name='Debug'):
        return self._log_attr.get(log_name, None)

    def getRunningXML(self):
        return self._user_xml

    def getRunningMacro(self):
        return self._running_macro

    def getLastRunningMacro(self):
        return self._last_running_macro

    def abort(self, synch=True):
        if not synch:
            self.command_inout("AbortMacro")
            return

        evt_wait = AttributeEventWait(self.getAttribute("state"))
        evt_wait.lock()
        try:
            time_stamp = time.time()
            self.command_inout("AbortMacro")
            evt_wait.waitEvent(self.Running, equal=False, after=time_stamp,
                               timeout=self.InteractiveTimeout)
        finally:
            evt_wait.unlock()
            evt_wait.disconnect()

    def stop(self, synch=True):
        if not synch:
            self.command_inout("StopMacro")
            return

        evt_wait = AttributeEventWait(self.getAttribute("state"))
        evt_wait.lock()
        try:
            time_stamp = time.time()
            self.command_inout("StopMacro")
            evt_wait.waitEvent(self.Running, equal=False, after=time_stamp,
                               timeout=self.InteractiveTimeout)
        finally:
            evt_wait.unlock()
            evt_wait.disconnect()

    def _clearRunMacro(self):
        # Clear the log buffer
        map(LogAttr.clearLogBuffer, self._log_attr.values())
        self._running_macros = None
        self._running_macro = None
        self._user_xml = None
        self._block_lines = 0

    def _createMacroXml(self, macro_name, macro_params):
        """The best effort creation of the macro XML object. It tries to
        convert flat list of string parameter values to the correct macro XML
        object. The cases that can not be converted are:
            * repeat parameter containing repeat parameters
            * two repeat parameters
            * repeat parameter that is not the last parameter

        :param macro_name: (str) macro name
        :param macro_params: (sequence[str]) list of parameter values

        :return (lxml.etree._Element) macro XML element
        """
        macro_info = self.macro_server.getMacroInfoObj(macro_name)
        params_def = macro_info.parameters
        macro_node = createMacroNode(macro_name, params_def, macro_params)
        return macro_node.toXml()

    def preRunMacro(self, obj, parameters):
        self._clearRunMacro()

        xml_root = None
        if isinstance(obj , (str, unicode)):
            if obj.startswith('<') and not parameters:
                xml_root = etree.fromstring(obj)
            else:
                macros = []
                if len(parameters) == 0:
                    macros_strs = obj.split('\n')
                    for m in macros_strs:
                        pars = m.split()
                        macros.append((pars[0], pars[1:]))
                else:
                    parameters = map(str, parameters)
                    macros.append((obj, parameters))
                xml_root = xml_seq = etree.Element('sequence')
                for m in macros:
                    macro_name = m[0]
                    macro_params = m[1]
                    xml_macro = self._createMacroXml(macro_name, macro_params)
                    xml_macro.set('id', str(uuid.uuid1()))
                    xml_seq.append(xml_macro)
        elif etree.iselement(obj):
            xml_root = obj
        else:
            raise TypeError('obj must be a string or a etree.Element')

        self._running_macros = {}
        for macro_xml in xml_root.xpath('//macro'):
            id, name = macro_xml.get('id'), macro_xml.get('name')
            self._running_macros[id] = Macro(self, name, id, macro_xml)
        return xml_root

    def postRunMacro(self, result, synch):
        pass

    def runMacro(self, obj, parameters=[], synch=False):
        self._user_xml = self.preRunMacro(obj, parameters)
        result = self._runMacro(self._user_xml, synch=synch)
        return self.postRunMacro(result, synch)

    def _runMacro(self, xml, synch=False):
        if not synch:
            return self.command_inout("RunMacro", [etree.tostring(xml)])
        timeout = self.InteractiveTimeout
        evt_wait = self._getEventWait()
        evt_wait.connect(self.getAttribute("state"))
        evt_wait.lock()
        try:
            evt_wait.waitEvent(self.Running, equal=False, timeout=timeout)
            ts = time.time()
            result = self.command_inout("RunMacro", [etree.tostring(xml)])
            evt_wait.waitEvent(self.Running, after=ts, timeout=timeout)
            if synch:
                evt_wait.waitEvent(self.Running, equal=False, after=ts,
                                   timeout=timeout)
        finally:
            self._clearRunMacro()
            evt_wait.unlock()
            evt_wait.disconnect()
        return result

    def stateChanged(self, s, t, v):
        self._old_door_state = self.getState()
        try:
            self._old_sw_door_state = self.getSWState()
        except:
            # TODO: For Taurus 4 compatibility
            self._old_sw_door_state = self.state

    def resultReceived(self, log_name, result):
        """Method invoked by the arrival of a change event on the Result attribute"""
        if self._ignore_logs or self._running_macro is None:
            return
        self._running_macro.setResult(result)
        return result

    def putEnvironment(self, name, value):
        self.macro_server.putEnvironment(name, value)

    def putEnvironments(self, obj):
        self.macro_server.putEnvironments(obj)

    setEnvironment = putEnvironment
    setEnvironments = putEnvironments

    def getEnvironment(self, name=None):
        return self.macro_server.getEnvironment(name=name)

    def inputReceived(self, s, t, v):
        if t not in CHANGE_EVT_TYPES:
            return
        if v is None or self._running_macros is None:
            return
        input_data = CodecFactory().decode(('json', v.value))
        self.processInput(input_data)

    def processInput(self, input_data):
        TaurusManager().addJob(self._processInput, None, input_data)

    def _processInput(self, input_data):
        input_type = input_data['type']
        if input_type == 'input':
            result = self._input_handler.input(input_data)
            if result['input'] is '' and 'default_value' in input_data:
                result['input'] = input_data['default_value']
            result = CodecFactory().encode('json', ('', result))[1]
            self.write_attribute('Input', result)
        elif input_type == 'timeout':
            self._input_handler.input_timeout(input_data)

    def recordDataReceived(self, s, t, v):
        if t not in CHANGE_EVT_TYPES: return
        return self._processRecordData(v)

    def _processRecordData(self, data):
        if data is None or data.value is None: return
        # make sure we get it as string since PyTango 7.1.4 returns a buffer
        # object and json.loads doesn't support buffer objects (only str)
        data = map(str, data.value)

        size = len(data[1])
        if size == 0: return
        format = data[0]
        codec = CodecFactory().getCodec(format)
        data = codec.decode(data)
        return data

    def processRecordData(self, data):
        pass

    def macroStatusReceived(self, s, t, v):
        if v is None or self._running_macros is None:
            return
        if t not in CHANGE_EVT_TYPES: return

        # make sure we get it as string since PyTango 7.1.4 returns a buffer
        # object and json.loads doesn't support buffer objects (only str)
        v = map(str, v.value)
        if not len(v[1]):
            return
        format = v[0]
        codec = CodecFactory().getCodec(format)

        # make sure we get it as string since PyTango 7.1.4 returns a buffer
        # object and json.loads doesn't support buffer objects (only str)
        v[1] = str(v[1])
        fmt, data = codec.decode(v)
        for macro_status in data:
            id = macro_status.get('id')
            macro = self._running_macros.get(id)
            self._last_running_macro = self._running_macro = macro
            # if we don't have the ID it's because the macro is running a submacro
            # or another client is connected to the same door (shame on him!) and
            # executing a macro we discard this event
            if macro is not None:
                macro.__dict__.update(macro_status)
        return data

    def logReceived(self, log_name, output):
        if not output or self._silent or self._ignore_logs:
            return

        if log_name == self.Debug and not self._debug:
            return

        o = self.log_start[log_name]
        for line in output:
            if not self._debug:
                if line == self.BlockStart:
                    self._in_block = True
                    for i in xrange(self._block_lines):
                        o += '\x1b[2K\x1b[1A\x1b[2K'  #erase current line, up one line, erase current line
                    self._block_lines = 0
                    continue
                elif line == self.BlockFinish:
                    self._in_block = False
                    continue
                else:
                    if self._in_block:
                        self._block_lines += 1
                    else:
                        self._block_lines = 0
            o += "%s\n" % line

        o += self.log_stop[log_name]
        self.write(o)

    def write(self, msg, stream=None):
        if self.isSilent():
            return
        msg = msg.encode('utf-8')
        self._output_stream = sys.stdout
        out = self._output_stream
        if not stream is None:
            start, stop = self.log_start.get(stream), self.log_stop.get(stream)
            if start is not None and stop is not None:
                out.write(start)
                out.write(msg)
                out.write(stop)
                out.flush()
                return
        out.write(msg)
        out.flush()

    def writeln(self, msg='', stream=None):
        self.write("%s\n" % msg, stream=stream)

    def getExperimentConfigurationObj(self):
        return self._experiment_configuration

    def getExperimentConfiguration(self):
        return self._experiment_configuration.get()

    def setExperimentConfiguration(self, config, mnt_grps=None):
        self._experiment_configuration.set(config, mnt_grps=mnt_grps)
Exemple #48
0
 def __init__(self, other=None):
     super(TangoDevTree, self).__init__()
     self._devices = CaselessDict()
     if other is not None:
         self._update(other)
Exemple #49
0
 def getElementsOfTypes(self, elem_types):
     elems = CaselessDict()
     for elem_type in elem_types:
         elems.update(self.getElementsOfType(elem_type))
     return elems
Exemple #50
0
    def remove_unwanted_dynamic_attributes(self, new_std_attrs, new_dyn_attrs):
        """Removes unwanted dynamic attributes from previous device creation"""

        dev_class = self.get_device_class()
        multi_attr = self.get_device_attr()
        multi_class_attr = dev_class.get_class_attr()
        static_attr_names = map(str.lower, dev_class.attr_list.keys())
        static_attr_names.extend(('state', 'status'))

        new_attrs = CaselessDict(new_std_attrs)
        new_attrs.update(new_dyn_attrs)

        device_attr_names = []
        for i in range(multi_attr.get_attr_nb()):
            device_attr_names.append(multi_attr.get_attr_by_ind(i).get_name())

        for attr_name in device_attr_names:
            attr_name_lower = attr_name.lower()
            if attr_name_lower in static_attr_names:
                continue
            try:
                self.remove_attribute(attr_name)
            except:
                self.warning("Error removing dynamic attribute %s",
                             attr_name_lower)
                self.debug("Details:", exc_info=1)

        klass_attr_names = []
        klass_attrs = multi_class_attr.get_attr_list()
        for ind in range(len(klass_attrs)):
            klass_attr_names.append(klass_attrs[ind].get_name())

        for attr_name in klass_attr_names:
            attr_name_lower = attr_name.lower()
            if attr_name_lower in static_attr_names:
                continue
            # if new dynamic attribute is in class attribute then delete it
            # from class attribute to be later on added again (eventually
            # with diffent data type or data format)
            if attr_name_lower in new_attrs:
                try:
                    attr = multi_class_attr.get_attr(attr_name)

                    old_type = CmdArgType(attr.get_type())
                    old_format = attr.get_format()
                    old_access = attr.get_writable()

                    new_attr = new_attrs[attr_name]
                    new_type, new_format, new_access = new_attr[1][0][:3]
                    differ = new_type != old_type or \
                             new_format != old_format or \
                             new_access != old_access
                    if differ:
                        self.info("Replacing dynamic attribute %s", attr_name)
                        self.debug("old type: %s, new type: %s",
                                   old_type, new_type)
                        self.debug("old format: %s, new format: %s",
                                   old_format, new_format)
                        self.debug("old access: %s, new access: %s",
                                   old_access, new_access)
                        multi_class_attr.remove_attr(attr.get_name(),
                                                     attr.get_cl_name())
                except:
                    self.warning("Error removing dynamic attribute %s from "\
                                 " device class", attr_name)
                    self.debug("Details:", exc_info=1)