#!/usr/bin/env python
#############################################################################
##
## This file is part of Taurus
##
## http://taurus-scada.org
##
## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
## Taurus is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## Taurus is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with Taurus. If not, see <http://www.gnu.org/licenses/>.
##
#############################################################################
"""This module contains the base class for a taurus database"""
__all__ = ["TaurusInfo", "TaurusDevInfo", "TaurusServInfo", "TaurusDevClassInfo",
"TaurusAttrInfo", "TaurusDevTree", "TaurusServerTree",
"TaurusDatabaseCache", "TaurusDatabase"]
__docformat__ = "restructuredtext"
import weakref
import operator
from .taurusbasetypes import TaurusEventType, TaurusSWDevHealth, TaurusElementType
from .taurusmodel import TaurusModel
from .util.containers import CaselessDict
DFT_DATABASE_DESCRIPTION = "A database"
[docs]class TaurusInfo(object):
def __init__(self, container, name=None, full_name=None):
self._container = weakref.ref(container)
self._name = name
self._full_name = full_name
[docs] def container(self):
return self._container()
[docs] def name(self):
return self._name
[docs] def fullName(self):
return self._full_name
def __str__(self): return "%s(%s)" % (self.__class__.__name__, self.name())
__repr__ = __str__
[docs]class TaurusDevInfo(TaurusInfo):
def __init__(self, container, name=None, full_name=None, alias=None, server=None, klass=None, exported=False, host=None):
super(TaurusDevInfo, self).__init__(container, name=name, full_name=full_name)
self._alias = alias
self._server = weakref.ref(server)
self._klass = weakref.ref(klass)
self._exported = bool(int(exported))
self._alive = None
self._health = None
self._host = host
self._domain, self._family, self._member = map(str.upper, name.split("/", 2))
self._attributes = None
[docs] def domain(self):
return self._domain
[docs] def family(self):
return self._family
[docs] def member(self):
return self._member
[docs] def alias(self):
return self._alias
[docs] def server(self):
return self._server()
[docs] def klass(self):
return self._klass()
[docs] def exported(self):
return self._exported
[docs] def alive(self):
return self._alive
[docs] def health(self):
if self._health is None:
if self.exported():
alive = self.alive()
if alive == True:
self._health = TaurusSWDevHealth.ExportedAlive
elif alive == False:
self._health = TaurusSWDevHealth.ExportedNotAlive
else:
self._health = TaurusSWDevHealth.Exported
else:
self._health = TaurusSWDevHealth.NotExported
return self._health
[docs] def host(self):
return self._host
[docs] def attributes(self):
return self._attributes
[docs] def getAttribute(self, attrname):
attrname= attrname.lower()
for a in self.attributes():
if a.name() == attrname:
return a
return None
[docs] def setAttributes(self, attributes):
self._attributes = attributes
[docs]class TaurusServInfo(TaurusInfo):
def __init__(self, container, name=None, full_name=None):
super(TaurusServInfo, self).__init__(container, name=name, full_name=full_name)
self._devices = CaselessDict()
self._exported = False
self._alive = None
self._host = ""
self._server_name, self._server_instance = name.split("/", 1)
[docs] def devices(self):
return self._devices
[docs] def getDeviceNames(self):
if not hasattr(self, "_device_name_list"):
self._device_name_list = sorted(map(TaurusDevInfo.name, self._devices.values()))
return self._device_name_list
[docs] def getClassNames(self):
if not hasattr(self, "_klass_name_list"):
klasses = set(map(TaurusDevInfo.klass, self._devices.values()))
self._klass_name_list = sorted(map(TaurusDevClassInfo.name, klasses))
return self._klass_name_list
[docs] def exported(self):
return self._exported
[docs] def alive(self):
return self._alive
[docs] def health(self):
exported = self.exported()
if exported:
alive = self.alive()
if alive == True:
return TaurusSWDevHealth.ExportedAlive
elif alive == False:
return TaurusSWDevHealth.ExportedNotAlive
else:
return TaurusSWDevHealth.Exported
return TaurusSWDevHealth.NotExported
[docs] def host(self):
return self._host
[docs] def serverName(self):
return self._server_name
[docs] def serverInstance(self):
return self._server_instance
[docs] def addDevice(self, dev):
self._exported |= dev.exported()
self._host = dev.host()
self._devices[dev.name()] = dev
[docs]class TaurusDevClassInfo(TaurusInfo):
def __init__(self, container, name=None, full_name=None):
super(TaurusDevClassInfo, self).__init__(container, name=name, full_name=full_name)
self._devices = CaselessDict()
[docs] def devices(self):
return self._devices
[docs] def getDeviceNames(self):
if not hasattr(self, "_device_name_list"):
self._device_name_list = sorted(map(TaurusDevInfo.name, self._devices.values()))
return self._device_name_list
[docs] def addDevice(self, dev):
self._devices[dev.name()] = dev
[docs]class TaurusAttrInfo(TaurusInfo):
def __init__(self, container, name=None, full_name=None, device=None, info=None):
super(TaurusAttrInfo, self).__init__(container, name=name, full_name=full_name)
self._info = info
self._device = weakref.ref(device)
[docs] def device(self):
return self._device()
[docs] def info(self):
return self._info
def __getattr__(self, name):
return getattr(self._info, name)
[docs]class TaurusDevTree(CaselessDict):
def __init__(self, other=None):
super(TaurusDevTree, self).__init__()
self._devices = CaselessDict()
if other is not None:
self._update(other)
def _update(self, other):
try:
if operator.isMappingType(other):
other = other.values()
for dev in other:
try:
self.addDevice(dev)
except Exception, e:
print e
except Exception, e:
raise Exception("Must give dict<obj, TaurusDevInfo> or sequence<TaurusDevInfo>")
[docs] def addDevice(self, dev_info):
domain, family, member = dev_info.domain(), dev_info.family(), dev_info.member()
families = self[domain] = self.get(domain, CaselessDict())
devs = self._devices[domain] = self._devices.get(domain, CaselessDict())
devs[dev_info.name()] = dev_info
families[family] = members = families.get(family, CaselessDict())
members[member] = dev_info
[docs] def getDomainDevices(self, domain):
"""Returns all devices under the given domain. Returns empty list if
the domain doesn't exist or doesn't contain any devices"""
return self._devices.get(domain, {}).values()
[docs] def getFamilyDevices(self, domain, family):
"""Returns all devices under the given domain/family. Returns empty list if
the domain/family doesn't exist or doesn't contain any devices"""
families = self.get(domain)
if families is None:
return
return families.get(family, {}).values()
[docs]class TaurusServerTree(dict):
def __init__(self, other=None):
super(TaurusServerTree, self).__init__()
if other is not None:
self._update(other)
def _update(self, other):
try:
if operator.isMappingType(other):
other = other.values()
for serv in other:
try:
self.addServer(serv)
except Exception, e:
print e
except Exception, e:
raise Exception("Must give dict<obj, TaurusServInfo> or sequence<TaurusServInfo>")
[docs] def addServer(self, serv_info):
serverName, serverInstance = serv_info.serverName(), serv_info.serverInstance()
serverInstances = self[serverName] = self.get(serverName, {})
serverInstances[serverInstance] = serv_info
[docs] def getServerNameInstances(self, serverName):
"""Returns all servers under the given serverName. Returns empty list if
the server name doesn't exist or doesn't contain any instances"""
return self.get(serverName, {}).values()
[docs]class TaurusDatabaseCache(object):
def __init__(self, db):
self._db = weakref.ref(db)
self._device_tree = None
self._server_tree = None
self._servers = None
self._server_name_list = None
self._devices = None
self._device_name_list = None
self._klasses = None
self._klass_name_list = None
self._aliases = None
self._alias_name_list = None
self.refresh()
@property
def db(self):
return self._db()
[docs] def refresh(self):
raise RuntimeError("Must be implemented in subclass")
[docs] def refreshAttributes(self, device):
raise RuntimeError("Must be implemented in subclass")
[docs] def getDevice(self, name):
"""Returns a :class:`taurus.core.taurusdatabase.TaurusDevInfo` object with information
about the given device name
:param name: (str) the device name
:return: (TaurusDevInfo) information about the device"""
return self._devices.get(name)
[docs] def getDeviceNames(self):
"""Returns a list of registered device names
:return: (sequence<str>) a sequence with all registered device names"""
if self._device_name_list is None:
self._device_name_list = sorted(map(TaurusDevInfo.name, self.devices().values()))
return self._device_name_list
[docs] def getAliasNames(self):
if self._alias_name_list is None:
self._alias_name_list = sorted(map(TaurusDevInfo.alias, self.aliases().values()))
return self._alias_name_list
[docs] def getServerNames(self):
"""Returns a list of registered server names
:return: (sequence<str>) a sequence with all registered server names"""
if self._server_name_list is None:
self._server_name_list = sorted(map(TaurusServInfo.name, self.servers().values()))
return self._server_name_list
[docs] def getClassNames(self):
"""Returns a list of registered device classes
:return: (sequence<str>) a sequence with all registered device classes"""
if self._klass_name_list is None:
self._klass_name_list = sorted(map(TaurusDevClassInfo.name, self.klasses().values()))
return self._klass_name_list
[docs] def deviceTree(self):
"""Returns a tree container with all devices in three levels: domain,
family and member
:return: (TaurusDevTree) a tree containning all devices"""
return self._device_tree
[docs] def serverTree(self):
"""Returns a tree container with all servers in two levels: server name
and server instance
:return: (TaurusServerTree) a tree containning all servers"""
return self._server_tree
[docs] def servers(self):
return self._servers
[docs] def devices(self):
return self._devices
[docs] def klasses(self):
return self._klasses
[docs] def getDeviceDomainNames(self):
return self._device_tree.keys()
[docs] def getDeviceFamilyNames(self, domain):
families = self._device_tree.get(domain)
if families is None: return []
return families.keys()
[docs] def getDeviceMemberNames(self, domain, family):
families = self._device_tree.get(domain)
if families is None: return []
members = families.get(family)
if members is None: return []
return members.keys()
[docs] def getDomainDevices(self, domain):
return self.deviceTree().getDomainDevices(domain)
[docs] def getFamilyDevices(self, domain, family):
return self.deviceTree().getFamilyDevices(domain, family)
[docs] def getServerNameInstances(self, serverName):
return self.serverTree().getServerNameInstances(serverName)
[docs]class TaurusDatabase(TaurusModel):
def __init__(self, complete_name, parent=None):
self._descr = None
self.call__init__(TaurusModel, complete_name, parent)
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
# TaurusModel implementation
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
[docs] def cleanUp(self):
self.trace("[TaurusDatabase] cleanUp")
TaurusModel.cleanUp(self)
@classmethod
[docs] def getTaurusElementType(cls):
return TaurusElementType.Database
@classmethod
[docs] def buildModelName(cls, parent_model, relative_name):
"""build an 'absolute' model name from the parent name and the 'relative'
name. parent_model is ignored since there is nothing above the Database
object"""
return relative_name
@classmethod
[docs] def getNameValidator(cls):
from .taurusvalidator import DatabaseNameValidator
return DatabaseNameValidator()
[docs] def getDescription(self,cache=True):
if self._descr is None or not cache:
try:
self._descr = self.info()
except:
self._descr = self._getDefaultDescription()
return self._descr
[docs] def getDisplayValue(self,cache=True):
return self.getDisplayDescription(cache)
[docs] def getDisplayDescription(self,cache=True):
return self.getFullName()
[docs] def getDisplayDescrObj(self,cache=True):
obj = []
obj.append(('name', self.getDisplayName(cache=cache)))
descr = self.getDescription(cache=cache)
obj.append(('description', descr))
return obj
[docs] def addListener(self, listener):
ret = TaurusModel.addListener(self, listener)
if not ret:
return ret
self.fireEvent(TaurusEventType.Change, self.getDisplayValue(), listener)
return ret
[docs] def getChildObj(self,child_name):
if not child_name:
return None
return self.getDevice(child_name)
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
# Device access methods
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
def getDevice(self, devname):
"""Returns the device object given its name"""
import taurusdevice
return self.factory().getObject(taurusdevice.TaurusDevice, devname)
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
# Query capabilities built on top of a cache
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
[docs] def refreshCache(self):
self.cache().refresh()
[docs] def getDevice(self, name):
"""Returns a :class:`taurus.core.tango.TangoDevInfo` object with information
about the given device name
:param name: (str) the device name
:return: (TangoDevInfo) information about the tango device"""
return self.cache().getDevice(name)
[docs] def getDeviceNames(self):
"""Returns a list of registered tango device names
:return: (sequence<str>) a sequence with all registered tango device names"""
return self.cache().getDeviceNames()
[docs] def getAliasNames(self):
"""Returns a list of registered tango device alias
:return: (sequence<str>) a sequence with all registered tango device alias"""
return self.cache().getAliasNames()
[docs] def getServerNames(self):
"""Returns a list of registered tango device servers in format<name>/<instance>
:return: (sequence<str>) a sequence with all registered tango device servers"""
return self.cache().getServerNames()
[docs] def getClassNames(self):
"""Returns a list of registered tango device classes
:return: (sequence<str>) a sequence with all registered tango device classes"""
return self.cache().getClassNames()
[docs] def getDeviceDomainNames(self):
return self.cache().getDeviceDomainNames()
[docs] def getDeviceFamilyNames(self, domain):
return self.cache().getDeviceFamilyNames(domain)
[docs] def getDeviceMemberNames(self, domain, family):
return self.cache().getDeviceMemberNames(domain, family)
[docs] def getDomainDevices(self, domain):
return self.cache().getDomainDevices(domain)
[docs] def getFamilyDevices(self, domain, family):
return self.cache().getFamilyDevices(domain, family)
[docs] def getServerNameInstances(self, serverName):
return self.cache().getServerNameInstances(serverName)
[docs] def deviceTree(self):
"""Returns a tree container with all devices in three levels : domain,
family and member
:return: (TangoDevTree) a tree containning all devices"""
return self.cache().deviceTree()
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
# Mandatory methods to overwrite
#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
[docs] def cache(self):
raise RuntimeError("TaurusDatabase.cache cannot be called")
[docs] def getElementAlias(self, full_name):
raise RuntimeError("TaurusDatabase.getElementAlias cannot be called")
[docs] def getElementFullName(self, alias):
raise RuntimeError("TaurusDatabase.getElementFullName cannot be called")
def _getDefaultDescription(self):
return DFT_DATABASE_DESCRIPTION