diff -Nru taurus-3.0.0/LICENSE.txt taurus-3.1.0/LICENSE.txt --- taurus-3.0.0/LICENSE.txt 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/LICENSE.txt 2013-07-25 07:53:44.000000000 +0000 @@ -13,7 +13,7 @@ ===================== Some files (e.g., those authored by 3rd parties or the documentation -sources) are distributed under Free Software / docmentation licenses +sources) are distributed under Free Software / documentation licenses that may differ from the the general one defined in SECTION 1. The following is a list of these exceptions: diff -Nru taurus-3.0.0/PKG-INFO taurus-3.1.0/PKG-INFO --- taurus-3.0.0/PKG-INFO 2012-04-30 07:51:56.000000000 +0000 +++ taurus-3.1.0/PKG-INFO 2013-07-25 08:09:45.000000000 +0000 @@ -1,10 +1,10 @@ Metadata-Version: 1.1 Name: taurus -Version: 3.0.0 +Version: 3.1.0 Summary: A library designed to provide an abstraction layer over PyTango. Home-page: http://packages.python.org/taurus -Author: Tiago Coutinho -Author-email: tcoutinho@cells.es +Author: Carlos Pascual-Izarra +Author-email: cpascual@cells.es License: LGPL Download-URL: http://pypi.python.org/packages/source/t/taurus Description: Taurus stands for TAngo User interface 'R' US. It diff -Nru taurus-3.0.0/debian/changelog taurus-3.1.0/debian/changelog --- taurus-3.0.0/debian/changelog 2013-01-22 22:46:09.000000000 +0000 +++ taurus-3.1.0/debian/changelog 2013-07-25 19:25:54.000000000 +0000 @@ -1,3 +1,18 @@ +taurus (3.1.0-1) unstable; urgency=low + + * Imported Upstream version 3.1.0 + * debian/control + - Remove python-all and python-numpy version constraints now that they + are fullfiled in all supported Debian versions. + - Switch to compat level 9 + - Bump Standards-Version to 3.9.4 (nothing to do) + * Remove patches applyed by the upstream + - 0001-forwarded-add-no-doc-option.patch (deleted) + - 0002-upstream-fix-for-the-FTBFS-due-to-image-conversion.patch (deleted) + - 0003-upstream-fix-tango-icon-resources.patch (deleted) + + -- Picca Frédéric-Emmanuel Sun, 24 Feb 2013 18:28:28 +0100 + taurus (3.0.0-2) unstable; urgency=low * Fix FTBFS with inkscape (Closes: #698462) diff -Nru taurus-3.0.0/debian/compat taurus-3.1.0/debian/compat --- taurus-3.0.0/debian/compat 2012-05-06 11:45:13.000000000 +0000 +++ taurus-3.1.0/debian/compat 2013-07-25 19:25:54.000000000 +0000 @@ -1 +1 @@ -8 +9 diff -Nru taurus-3.0.0/debian/control taurus-3.1.0/debian/control --- taurus-3.0.0/debian/control 2013-01-16 20:23:10.000000000 +0000 +++ taurus-3.1.0/debian/control 2013-07-25 19:25:54.000000000 +0000 @@ -3,25 +3,25 @@ Uploaders: Picca Frédéric-Emmanuel Section: science Priority: extra -Build-Depends: debhelper (>= 8), +Build-Depends: debhelper (>= 9), graphviz, imagemagick, inkscape, libqt4-dev, pymca, pyqt4-dev-tools, - python-all (>= 2.6.6-3~), + python-all, python-guiqwt, python-h5py, python-lxml, - python-numpy (>=1:1.4.1-4), + python-numpy, python-ply, python-pytango, python-qt4, python-qwt5-qt4, python-sphinx, python-spyderlib -Standards-Version: 3.9.3 +Standards-Version: 3.9.4 Homepage: http://www.tango-controls.org X-Python-Version: >= 2.6 @@ -34,7 +34,7 @@ python-h5py, python-lxml, python-ply, - python-pytango (>= 7.2.3-1), + python-pytango, python-qt4, python-qwt5-qt4, python-spyderlib diff -Nru taurus-3.0.0/debian/gbp.conf taurus-3.1.0/debian/gbp.conf --- taurus-3.0.0/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/debian/gbp.conf 2013-07-25 19:26:29.000000000 +0000 @@ -0,0 +1,2 @@ +[DEFAULT] +debian-branch=master diff -Nru taurus-3.0.0/debian/patches/0001-forwarded-add-no-doc-option.patch taurus-3.1.0/debian/patches/0001-forwarded-add-no-doc-option.patch --- taurus-3.0.0/debian/patches/0001-forwarded-add-no-doc-option.patch 2013-01-22 22:52:55.000000000 +0000 +++ taurus-3.1.0/debian/patches/0001-forwarded-add-no-doc-option.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -From: Debian Science Maintainers - -Date: Wed, 16 Jan 2013 17:03:02 +0100 -Subject: forwarded-add-no-doc-option - ---- - setup.py | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/setup.py b/setup.py -index d64b7ee..c3afb89 100644 ---- a/setup.py -+++ b/setup.py -@@ -473,12 +473,14 @@ class install(dftinstall): - - user_options = list(dftinstall.user_options) - user_options.extend([ -- ('install-man=', None, 'installation directory for Unix man pages'), -- ('install-html=', None, "installation directory for HTML documentation")]) -+ ('install-man=', None, 'installation directory for Unix man pages'), -+ ('install-html=', None, "installation directory for HTML documentation"), -+ ('no-doc', None, "do not install HTML documentation")]) - - def initialize_options(self): - self.install_man = None - self.install_html = None -+ self.no_doc = None - dftinstall.initialize_options(self) - - def finalize_options(self): -@@ -503,6 +505,8 @@ class install(dftinstall): - self.install_man = os.path.join(self.install_data, 'share', 'man') - if self.install_html is None: - self.install_html = os.path.join(self.install_data, 'share', 'doc', 'taurus', 'html') -+ if self.no_doc is None: -+ self.no_doc = False - self.dump_dirs("Installation directories") - - def expand_dirs(self): -@@ -513,6 +517,8 @@ class install(dftinstall): - return os.name == "posix" - - def has_html(self): -+ if self.no_doc: -+ return False - return sphinx is not None - - sub_commands = list(dftinstall.sub_commands) -@@ -778,7 +784,7 @@ def svg_to_png(arg, dirname, fnames): - full_target_fname = os.path.join(path, target_fname) - if not os.path.isfile(full_target_fname): - if use_inkscape: -- cmd = "inkscape -z -e '%s' -w 24 '%s' &>/dev/null"%(full_target_fname, full_source_fname) -+ cmd = "inkscape -z -e '%s' -w 24 '%s' > /dev/null"%(full_target_fname, full_source_fname) - ok = not(os.system(cmd)) - else: - pixmap = PyQt4.Qt.QPixmap(full_source_fname) diff -Nru taurus-3.0.0/debian/patches/0002-upstream-fix-for-the-FTBFS-due-to-image-conversion.patch taurus-3.1.0/debian/patches/0002-upstream-fix-for-the-FTBFS-due-to-image-conversion.patch --- taurus-3.0.0/debian/patches/0002-upstream-fix-for-the-FTBFS-due-to-image-conversion.patch 2013-01-22 22:52:55.000000000 +0000 +++ taurus-3.1.0/debian/patches/0002-upstream-fix-for-the-FTBFS-due-to-image-conversion.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -From: =?UTF-8?q?Picca=20Fr=C3=A9d=C3=A9ric-Emmanuel?= -Date: Tue, 22 Jan 2013 23:52:11 +0100 -Subject: upstream fix for the FTBFS due to image conversion - ---- - setup.py | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/setup.py b/setup.py -index c3afb89..19b1a54 100644 ---- a/setup.py -+++ b/setup.py -@@ -585,7 +585,6 @@ if sphinx: - def run(self): - self.resource_dir = abspath('lib', 'taurus', 'qt', 'qtgui', 'resource') - self.taurus = os.path.join(self.resource_dir, 'taurus.png') -- import PyQt4.Qt - orig_dir = os.path.abspath(os.curdir) - os.chdir(self.resource_dir) - -@@ -784,8 +783,11 @@ def svg_to_png(arg, dirname, fnames): - full_target_fname = os.path.join(path, target_fname) - if not os.path.isfile(full_target_fname): - if use_inkscape: -- cmd = "inkscape -z -e '%s' -w 24 '%s' > /dev/null"%(full_target_fname, full_source_fname) -+ cmd = "inkscape -z '%s' -e '%s' -w 24 >/dev/null 2>/dev/null"%(full_source_fname, full_target_fname) - ok = not(os.system(cmd)) -+ if not ok: -+ cmd = "convert -resize 24 '%s' '%s' >/dev/null 2>/dev/null"%(full_source_fname, full_target_fname) -+ ok = not(os.system(cmd)) - else: - pixmap = PyQt4.Qt.QPixmap(full_source_fname) - pix = pixmap.scaledToWidth(24, PyQt4.Qt.Qt.SmoothTransformation) diff -Nru taurus-3.0.0/debian/patches/0003-upstream-fix-tango-icon-resources.patch taurus-3.1.0/debian/patches/0003-upstream-fix-tango-icon-resources.patch --- taurus-3.0.0/debian/patches/0003-upstream-fix-tango-icon-resources.patch 2013-01-22 22:52:55.000000000 +0000 +++ taurus-3.1.0/debian/patches/0003-upstream-fix-tango-icon-resources.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,174 +0,0 @@ -From: =?UTF-8?q?Picca=20Fr=C3=A9d=C3=A9ric-Emmanuel?= -Date: Fri, 18 Jan 2013 21:13:40 +0100 -Subject: upstream fix tango icon resources - ---- - .../qt/qtgui/resource/taurus_resource_utils.py | 94 +++++++++----------- - 1 file changed, 44 insertions(+), 50 deletions(-) - -diff --git a/lib/taurus/qt/qtgui/resource/taurus_resource_utils.py b/lib/taurus/qt/qtgui/resource/taurus_resource_utils.py -index 5976544..42f8438 100644 ---- a/lib/taurus/qt/qtgui/resource/taurus_resource_utils.py -+++ b/lib/taurus/qt/qtgui/resource/taurus_resource_utils.py -@@ -47,7 +47,6 @@ DevHealth = taurus.core.TaurusSWDevHealth - Size = Qt.QSize - - __INITIALIZED = False --__INITIALIZED_THEME = False - # Theme capacity was only added in Qt 4.6 - __THEME_CAPACITY = hasattr(Qt.QIcon, "fromTheme") - # Uncomment the following line to force NOT to use OS theme. -@@ -66,60 +65,47 @@ __3DQS = Size(3*__DW, __DH) - - def __init(): - global __INITIALIZED -+ global __THEME_MEMBERS - - if __INITIALIZED: return -- -+ -+ #register only the tango-icons rcc files (and initialize the THEME_MEMBERS) - res_dir = os.path.dirname(os.path.abspath(__file__)) - Qt.QDir.addSearchPath("resource", res_dir) -- -- for res_file in [ f for f in os.listdir(res_dir) if f.endswith(".rcc") ]: -- if not Qt.QResource.registerResource("resource:" + res_file): -- __LOGGER.info("Failed to load resource %s" % res_file) -+ prefix = 'qrc_tango_icons_' -+ suffix = '.rcc' -+ lp, ls = len(prefix),len(suffix) -+ theme_members = {} -+ other_rcc_files = [] -+ for f in os.listdir(res_dir): -+ if f.endswith(suffix): -+ if f.startswith(prefix): -+ if Qt.QResource.registerResource("resource:" + f): -+ d = f[lp:-ls] -+ theme_members[d] = [str(e)[:-4] for e in Qt.QDir(":%s"%d).entryList() if str(e).endswith('.svg')] -+ else: -+ __LOGGER.info("Failed to load resource %s" % f) -+ else: -+ other_rcc_files.append(f) #we remember these and will register later -+ __THEME_MEMBERS = theme_members -+ -+ #register the rest of the resource files -+ for f in other_rcc_files: -+ if not Qt.QResource.registerResource("resource:" + f): -+ __LOGGER.info("Failed to load resource %s" % f) - - __INITIALIZED = True - - __init() - --def __init_theme_members(): -- global __INITIALIZED_THEME -- global __THEME_MEMBERS -- global __THEME_CAPACITY -- global __LOGGER -- -- if __INITIALIZED_THEME: return __THEME_MEMBERS -- -- app = Qt.QApplication.instance() -- if app is None and __THEME_CAPACITY: -- raise Exception("Cannot calculate theme without QApplication instance") -- -- res_dir = os.path.dirname(os.path.abspath(__file__)) -- theme_icon_dir = os.path.join(res_dir, "tango-icons") -- members = {} -- for d in os.listdir(theme_icon_dir): -- abs_dir = os.path.join(theme_icon_dir, d) -- if d[0] == "." or not os.path.isdir(abs_dir): -- continue -- elems = [] -- for elem in os.listdir(abs_dir): -- abs_elem = os.path.join(abs_dir, elem) -- idx = elem.rfind(".svg") -- if elem[0] == "." or idx < 0 or not os.path.isfile(abs_elem): -- continue -- elems.append(elem[:idx]) -- members[d] = elems -- -- __THEME_MEMBERS = members -- -- __INITIALIZED_THEME = True -- return __THEME_MEMBERS -- - def getThemeMembers(): - """Returns the current icon theme elements - - :return: the current icon theme elements in a dictionary where each key is - a group name and the value is a sequence of theme icon name. - :rtype: dict>""" -- return __init_theme_members() -+ global __THEME_MEMBERS -+ return __THEME_MEMBERS - - def getPixmap(key, size=None): - """Returns a PyQt4.QtGui.QPixmap object for the given key and size -@@ -168,13 +154,17 @@ def getThemePixmap(key, size=None): - :return: (PyQt4.QtGui.QPixmap) a PyQt4.QtGui.QPixmap for the given key and size""" - - global __THEME_CAPACITY -- if __THEME_CAPACITY and Qt.QIcon.hasThemeIcon(key): -- size = size or 48 -- return Qt.QIcon.fromTheme(key).pixmap(size, size) -- -+ global __LOGGER -+ if __THEME_CAPACITY: -+ if Qt.QIcon.hasThemeIcon(key): -+ size = size or 48 -+ return Qt.QIcon.fromTheme(key).pixmap(size, size) -+ else: -+ __LOGGER.debug('Theme pixmap "%s" not supported. Trying to provide a fallback...',key) - for member, items in getThemeMembers().items(): - if not key in items: continue - return getPixmap(":/%s/%s.svg" % (member, key), size) -+ __LOGGER.debug('Theme pixmap "%s" not supported.', key) - return Qt.QPixmap() - - def getThemeIcon(key): -@@ -192,12 +182,16 @@ def getThemeIcon(key): - :return: (PyQt4.QtGui.QIcon) a PyQt4.QtGui.QIcon for the given key""" - - global __THEME_CAPACITY -- if __THEME_CAPACITY and Qt.QIcon.hasThemeIcon(key): -- return Qt.QIcon.fromTheme(key) -- -+ global __LOGGER -+ if __THEME_CAPACITY: -+ if Qt.QIcon.hasThemeIcon(key): -+ return Qt.QIcon.fromTheme(key) -+ else: -+ __LOGGER.debug('Theme icon "%s" not supported. Trying to provide a fallback...',key) - for member, items in getThemeMembers().items(): - if not key in items: continue - return Qt.QIcon(":/%s/%s.svg" % (member, key)) -+ __LOGGER.debug('Theme icon "%s" not supported.', key) - return Qt.QIcon() - - def getStandardIcon(key, widget=None): -@@ -205,7 +199,7 @@ def getStandardIcon(key, widget=None): - QStyle.StandardPixmap enumeration member. The widget argument is optional - and can also be used to aid the determination of the icon. - -- :param key: (QStyle.StandardPixmap) a standard pixmap which can follow some existing GUI style or guidelin -+ :param key: (QStyle.StandardPixmap) a standard pixmap which can follow some existing GUI style or guideline - :param widget: (Qt.QWidget) the widget argument (optional) can also be used to aid the determination of the icon. - - :return: (PyQt4.QtGui.QIcon) a PyQt4.QtGui.QIcon for the given key""" -@@ -220,7 +214,7 @@ def getStandardIcon(key, widget=None): - __IDX_ELEM_TYPE_ICON, __IDX_ELEM_TYPE_SIZE, __IDX_ELEM_TYPE_TOOLTIP = range(3) - - # New default role map --# Elements are: icon theme, prefered size, description/tooltip -+# Elements are: icon theme, preferred size, description/tooltip - _ELEM_TYPE_MAP = { ElemType.Name : ("folder", __3DQS, None), - ElemType.Device : ("applications-system", Size(210, __DH), "Tango device name"), - ElemType.DeviceAlias : ("applications-system", Size(140, __DH), "Tango device alias"), -@@ -354,4 +348,4 @@ def getSWDevHealthPixmap(elemHealth, size=None): - if data is None: - return - themeName = data[__IDX_HEALTH_ICON] -- return getThemePixmap(themeName, size) -\ No newline at end of file -+ return getThemePixmap(themeName, size) diff -Nru taurus-3.0.0/debian/patches/series taurus-3.1.0/debian/patches/series --- taurus-3.0.0/debian/patches/series 2013-01-22 22:52:55.000000000 +0000 +++ taurus-3.1.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -0001-forwarded-add-no-doc-option.patch -0002-upstream-fix-for-the-FTBFS-due-to-image-conversion.patch -0003-upstream-fix-tango-icon-resources.patch diff -Nru taurus-3.0.0/debian/rules taurus-3.1.0/debian/rules --- taurus-3.0.0/debian/rules 2013-01-22 22:53:58.000000000 +0000 +++ taurus-3.1.0/debian/rules 2013-07-25 22:15:11.000000000 +0000 @@ -10,9 +10,18 @@ get-orig-source: uscan --force-download --upstream-version $(VERSION) +override_dh_auto_clean: + dh_auto_clean + rm -rf build + rm -f lib/taurus/qt/qtgui/resource/*.rcc + rm -f lib/taurus/qt/qtgui/resource/*.qrc + rm -rf doc/source/devel/api + rm -f doc/source/devel/catalog.html + rm -f lib/taurus/qt/qtgui/resource/catalog.html + override_dh_auto_build: - dh_auto_build -- --no-doc - python setup.py build_doc --use-inkscape + dh_auto_build -- --no-doc --with-extra-widgets + python setup.py build_doc --external-img-tools override_dh_auto_install: dh_auto_install -- --skip-build --no-doc diff -Nru taurus-3.0.0/doc/auto_rst4api.py taurus-3.1.0/doc/auto_rst4api.py --- taurus-3.0.0/doc/auto_rst4api.py 2012-04-30 07:46:22.000000000 +0000 +++ taurus-3.1.0/doc/auto_rst4api.py 2013-07-25 07:53:14.000000000 +0000 @@ -27,9 +27,14 @@ ''' Creates a tree of dirs and restructured text stub files for documenting the API of a python module with sphinx''' -import sys, os, inspect, glob, re +import sys, os from jinja2 import Environment, FileSystemLoader +#import ModuleExplorer from "../tests/modulexplorer.py" +from imp import load_source +mpath = os.path.abspath(os.path.join(os.path.dirname(__file__),os.path.pardir,'tests','moduleexplorer.py')) +ModuleExplorer = load_source('moduleexplorer', mpath).ModuleExplorer + class Auto_rst4API_Creator(object): AUTOGEN_SIGNATURE = '.. AUTO_RST4API' @@ -42,49 +47,18 @@ :param moduletemplate: (str) name of the template to be used for module pages :param classtemplate: (str) name of the template to be used for class pages :param classindextemplate: (str) name of the template to be used for class index page - :param exclude_patterns: (seq) sequence of strings containing regexp - patterns. Each candidate to be documented will be - matched against these patterns and will be excluded - from documentation if it matches any of them. :param verbose: (bool) If True (default) status messages will be printed to stdout ''' + + self.verbose = verbose + self.exclude_patterns = exclude_patterns + self.env = Environment(loader=FileSystemLoader(templatespath)) self.moduletemplate = self.env.get_template(moduletemplate) self.classtemplate = self.env.get_template(classtemplate) self.classindextemplate = self.env.get_template(classindextemplate) - self.exclude_patterns = [re.compile(p) for p in exclude_patterns] - self.verbose = verbose self.overwrite_old = overwrite_old - def _matchesAnyPattern(self, name, paterns): - for p in paterns: - if re.match(p,name) is not None: - if self.verbose: print 'excluding "%s"'%name - return True - return False - - def _getlocalmembernames(self, module, predicate=None): - ret =[] - modulepath, tail = os.path.split(inspect.getabsfile(module)) - for n,v in inspect.getmembers(module, predicate): - if inspect.isbuiltin(v): - continue #ignore builtin functions - try: - memberpath, tail = os.path.split(inspect.getabsfile(v)) - except TypeError: - continue #ignore builtin modules - if memberpath == modulepath: - ret.append(n) - return ret - - def _getSubmodulesFromPath(self, modulepath): - g = glob.glob(os.path.join(modulepath,'*','__init__.py')) - ret = [re.findall(r".+\/(.*)\/__init__.py", s)[0] for s in g] - return ret - - def _isclass_with_init(self, obj): - return inspect.isclass(obj) and hasattr(obj,'__init__') - def _isautogeneratedfile(self, fname): ret = False f = open(fname,'r') @@ -97,10 +71,6 @@ return ret - def _isenumeration(self, obj): -# return isinstance(obj, taurus.core.util) - return False #@todo - def cleanAutogenerated(self, apipath): '''Removes any previously autogenerated rst file in the given path or its subdirectories @@ -117,16 +87,6 @@ os.remove(fullname) except Exception, e: print 'Error accessing %s:%s'%(fullname,repr(e)) - - def getAll(self, info, key): - mname = info['modulename'] - try: - ret = [(mname,el) for el in info[key]] - except KeyError: - return [] - for sminfo in info['submodules'].itervalues(): - ret += self.getAll(sminfo,key) - return ret def createClassIndex(self, info, ofname ): ''' @@ -137,7 +97,7 @@ :meth:`exploreModule` :param ofname: (str) output file name ''' - classes = self.getAll(info, 'localclassnames') #this is a list of tuples of (modulename,class) + classes = ModuleExplorer.getAll(info, 'localclassnames') #this is a list of tuples of (modulename,class) classes = sorted(classes, key=lambda item: item[1]) #sort it by class name classes = ['.'.join((m,c)) for m,c in classes] # make a full classname if self.verbose: print 'creating "%s" ...'%ofname, @@ -149,68 +109,6 @@ if self.verbose: print ' ok.' else: if self.verbose: print ' skipping (file already exists)' - - - def exploreModule(self, modulename): - '''Recursive function that gathers info on a module and all its submodules. - - :param modulename: the name of the module to explore - - :return: (dict) a dictionary containing submodulenames, - localclassnames, localfunctionnames, localenumerationnames, - externalmembernames, submodules, warnings - ''' - if self.verbose: print "Exploring %s..."%modulename - warnings = [] - try: - module = __import__(modulename, fromlist = ['']) - except Exception,e: - msg = 'exploreModule: WARNING: skipping documentation for %s. Reason: %s'%(modulename,repr(e)) - warnings.append(msg) - if self.verbose: print msg - return dict(modulename = modulename, - basemodulename = modulename.split('.')[-1], - modulepath = None, - submodulenames = [], - localclassnames = [], - localfunctionnames = [], - localenumerationnames = [], - externalmembernames = [], - submodules = {}, - warnings = warnings) - modulepath, tail = os.path.split(inspect.getabsfile(module)) - - submodulenames = sorted(self._getSubmodulesFromPath(modulepath)) - localclassnames = sorted(self._getlocalmembernames(module, self._isclass_with_init)) - localfunctionnames = sorted(self._getlocalmembernames(module, inspect.isfunction)) - localenumerationnames = sorted([])#@todo - externalmembernames = sorted([]) #@todo -# localmembers = list(submodules) + localfunctionnames + localclassnames + localenumerationnames -# externalmembers = [n for n,v in inspect.getmembers(object) if (n not in localmembers and not n.startswith('_'))] - - #filter out excluded members - submodulenames = [n for n in submodulenames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] - localclassnames = [n for n in localclassnames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] - localfunctionnames = [n for n in localfunctionnames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] - localenumerationnames = [n for n in localenumerationnames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] - externalmembernames = [n for n in externalmembernames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] - - #recurse - submodules = {} - for n in submodulenames: - sm_name = '.'.join((modulename, n)) - submodules[n] = self.exploreModule(sm_name) - - return dict(modulename = modulename, - basemodulename = modulename.split('.')[-1], - modulepath = modulepath, - submodulenames = submodulenames, - localclassnames = localclassnames, - localfunctionnames = localfunctionnames, - localenumerationnames = localenumerationnames, - externalmembernames = externalmembernames, - submodules = submodules, - warnings = warnings) def createStubs(self, info, docparentpath): '''creates rst stub files for modules and classes according to the @@ -253,7 +151,7 @@ for sminfo in info['submodules'].itervalues(): self.createStubs(sminfo, absdocpath) - def documentModule(self, modulename, docparentpath): + def documentModule(self, modulename, docparentpath, exclude_patterns=()): ''' recursive function that walks on the module structure and generates documentation files for the given module and its submodules. It also @@ -262,95 +160,20 @@ :param modulename: (str) name of the module to document :docparentpath: (str) path to the directory in which the documentation files will be written + :param exclude_patterns: (seq) sequence of strings containing regexp + patterns. Each candidate to be documented will be + matched against these patterns and will be excluded + if it matches any of them. :return: (list) list of warning messages ''' - if self.verbose: print "\nDocumenting %s..."%modulename - moduleinfo = self.exploreModule(modulename) + if self.verbose: print "\nDocumenting %s..."%modulename + moduleinfo, w = ModuleExplorer.explore(modulename, exclude_patterns=self.exclude_patterns, verbose=self.verbose) self.createStubs(moduleinfo, docparentpath) self.createClassIndex(moduleinfo, os.path.join(docparentpath,"%s_AllClasses.rst"%modulename)) - w=self.getAll(moduleinfo, 'warnings') if len (w) == 0: return [] else: return zip(*w)[1] - - - -# def document_module_OLD(self, modulename, docparentpath): -# ''' -# recursive function that walks on the module structure and generates -# documentation files for the given module and its submodules -# -# :param modulename: (str) name of the module to document -# :docparentpath: (str) path to the directory in which the documentation -# files will be written -# -# :return: (list) list of warning messages -# ''' -# if self.verbose: print "\nDocumenting %s..."%modulename -# try: -# module = __import__(modulename, fromlist = ['']) -# except Exception,e: -# msg = 'WARNING: skipping documentation for %s. Reason: %s'%(modulename,repr(e)) -# self.warnings.append(msg) -# if self.verbose: print msg -# return self.warnings -# modulepath, tail = os.path.split(inspect.getabsfile(module)) -# basemodulename = modulename.split('.')[-1] -# absdocpath = os.path.join(docparentpath, basemodulename) -# -# submodules = self._getSubmodulesFromPath(modulepath) -# localclassnames = self._getlocalmembernames(module, self._isclass_with_init) -# localfunctionnames = self._getlocalmembernames(module, inspect.isfunction) -# localenumerationnames = []#@todo -# externalmembers = [] #@todo -## localmembers = list(submodules) + localfunctionnames + localclassnames + localenumerationnames -## externalmembers = [n for n,v in inspect.getmembers(object) if (n not in localmembers and not n.startswith('_'))] -# -# #filter out excluded members -# submodules = [n for n in submodules if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] -# localclassnames = [n for n in localclassnames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] -# localfunctionnames = [n for n in localfunctionnames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] -# localenumerationnames = [n for n in localenumerationnames if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] -# externalmembers = [n for n in externalmembers if not self._matchesAnyPattern(os.path.join(modulename,n), self.exclude_patterns)] -# -# #create the module doc dir if it didn't exist -# if not os.path.exists(absdocpath): -# os.makedirs(absdocpath, mode=0755) -# #create module index stub in doc parent dir -# text = self.moduletemplate.render(modulename=modulename, -# basemodulename=basemodulename, -# submodules=submodules, -# localclassnames=localclassnames, -# localfunctionnames=localfunctionnames, -# localenumerationnames=localenumerationnames, -# externalmembers = externalmembers -# ) -# ofname = os.path.join(docparentpath,"%s.rst"%basemodulename) -# if self.verbose: print 'creating "%s" ...'%ofname, -# if os.path.exists(ofname) and self._isautogeneratedfile(ofname): -# if self.verbose: print ' skipping (manually edited file already exists)' -# else: -# f = open(ofname, "w") -# f.write('\n'.join((self.AUTOGEN_SIGNATURE, self.AUTOGEN_MESSAGE, text))) -# f.close() -# if self.verbose: print ' ok.' -# #create class stubs -# for name in localclassnames: -# text = self.classtemplate.render(classname=name, modulename=modulename) -# ofname = os.path.join(absdocpath,"_%s.rst"%name) -# if self.verbose: print 'creating "%s" ...'%ofname, -# if os.path.exists(ofname) and self._isautogeneratedfile(ofname): -# if self.verbose: print ' skipping (manually edited file already exists)' -# else: -# f = open(ofname, "w") -# f.write('\n'.join((self.AUTOGEN_SIGNATURE, self.AUTOGEN_MESSAGE, text))) -# f.close() -# if self.verbose: print ' ok.' -# #recurse for submodules -# for sm in submodules: -# sm_name = '.'.join((modulename, sm)) -# self.documentModule(sm_name, absdocpath) -# return self.warnings + def main(): import sys @@ -358,12 +181,12 @@ print 'Usage:\n\t%s modulename docpreffix\n\n'%sys.argv[0] sys.exit(1) modulename, docparentpath = sys.argv[1:] - creator = Auto_rst4API_Creator(exclude_patterns = ['.*/ui'], verbose=True) - r = creator.documentModule(modulename, docparentpath) + creator = Auto_rst4API_Creator(verbose=True) + r = creator.documentModule(modulename, docparentpath, exclude_patterns = ['.*/ui']) print '\n\n'+'*'*50 print "Auto Creation of API docs for %s Finished with %i warnings:"%(modulename,len(r)) print '\n'.join(r) print '*'*50+'\n' -if __name__ == "__main__": +if __name__ == "__main__": main() \ No newline at end of file diff -Nru taurus-3.0.0/doc/source/conf.py taurus-3.1.0/doc/source/conf.py --- taurus-3.0.0/doc/source/conf.py 2012-04-30 07:46:22.000000000 +0000 +++ taurus-3.1.0/doc/source/conf.py 2013-07-25 07:53:14.000000000 +0000 @@ -244,6 +244,6 @@ 'http://docs.scipy.org/doc/scipy/reference' : None, 'http://docs.scipy.org/doc/numpy' : None, 'http://www.tango-controls.org/static/PyTango/latest/doc/html' : None, - 'http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html' : None, + 'http://pyqt.sourceforge.net/Docs/PyQt4/' : None, } diff -Nru taurus-3.0.0/doc/source/devel/coding_guide.rst taurus-3.1.0/doc/source/devel/coding_guide.rst --- taurus-3.0.0/doc/source/devel/coding_guide.rst 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/coding_guide.rst 2013-07-25 07:53:11.000000000 +0000 @@ -14,21 +14,32 @@ How to contribute to taurus ---------------------------- -Taurus development is done using SVN. Because taurus is part of Tango_, it uses -its `tango-cs sourceforge project `_ -to host the source code. This makes it easy for people to contribute to the -development of taurus. +Taurus is part of Tango_ and, more specifically, part of Sardana_. Until release +3.1 (included) the development of Taurus was managed within the `tango-cs +sourceforge project `_ and its +source code was hosted in the Tango SVN repository. Starting from right after +the Taurus 3.1 release, the source code hosting and general project management +(tickets, mailing list, etc) will be managed within the Sardana `Sardana +sourceforge project `_. The Sardana +project itself is in the process of migrating its source code hosting from SVN +to Git and consequently, Taurus code will be hosted on a Git repository after +the release of Taurus 3.1. + How to checkout taurus from SVN ------------------------------- +.. warning:: These instructions will become obsolete as soon as Taurus 3.1 + is released because the code development will be moved from SVN to + Git. Updated instructions for using Git will be posted ASAP. + **For read-only**:: - svn co https://tango-cs.svn.sourceforge.net/svnroot/tango-cs/taurus/trunk taurus + svn co https://svn.code.sf.net/p/tango-cs/code/gui/taurus/trunk taurus **To being able to commit**:: - svn co https://@tango-cs.svn.sourceforge.net/svnroot/tango-cs/taurus/trunk taurus + svn co https://@svn.code.sf.net/p/tango-cs/code/gui/taurus/trunk taurus .. note:: @@ -113,8 +124,89 @@ if __name__ == "__main__": main() +Special notes about Qt programming +----------------------------------- + +The following Qt guidelines are intended to ensure compatibility between all +PyQt4/PySide versions. + +1. Avoid importing PyQt4/PySide directly. + Imports like:: + + from PyQt4 import Qt + from PyQt4 import QtCore + from PyQt4 import QtGui + from PyQt4 import QtNetwork + from PyQt4 import QtWebKit + from PyQt4 import Qwt5 + + Should be replaced by:: + + from taurus.qt import Qt + from taurus.qt import QtCore + from taurus.qt import QtGui + from taurus.qt import QtNetwork + from taurus.qt import QtWebKit + from taurus.qt import Qwt5 + +2. Usage of :class:`~PyQt4.QString` is **discouraged**. You should always use + :class:`str`. QString objects don't exist in PySide or in the new PyQt4 + API 2. Code like:: + + my_string = Qt.QString(" hello ") + my_string2 = my_string.trimmed() + label.setText(my_string2) + print label.text() + + Should be replaced by:: + + my_string = " hello " + my_string2 = my_string.strip() + label.setText(my_string2) + print str(label.text()) # never assume Qt objects return str. + + For compatibility reasons, QString and QStringList are always available + (even when using PySide or PyQt4 with API >=2) from :mod:`taurus.qt.Qt`. + Note that if you are using PySide or PyQt4 with API >=2 then QString is + actually :class:`str` and QStringList is actually :class:`list`! + +3. Usage of :class:`~PyQt4.QVariant` is **discouraged**. QVariant objects + don't exist in PySide or in the new PyQt4 API 2. Code like:: + + def setData(self, index, qvalue, role=Qt.Qt.EditRole): + value = qvalue.toString() + self.buffer[index.column()] = value + + def data(self, index, role=Qt.Qt.DisplayRole): + value = self.buffer[index.column()] + + if role == Qt.Qt.DisplayRole: + return Qt.QVariant(value) + else: + return Qt.QVariant() + + Should be replaced by:: + + def setData(self, index, qvalue, role=Qt.Qt.EditRole): + value = Qt.from_qvariant(qvalue, str) + self.buffer[index.column()] = value + + def data(self, index, role=Qt.Qt.DisplayRole): + value = self.buffer[index.column()] + + if role == Qt.Qt.DisplayRole: + return Qt.to_qvariant(value) + else: + return Qt.from_qvariant() + + For compatibility reasons, QVariant are always available + (even when using PySide or PyQt4 with API >=2) from :mod:`taurus.qt.Qt`. + Note that if you are using PySide or PyQt4 with API >=2 then QVariant(pyobj) + if function that returns actually pyobj (exactly the same as + :func:`~taurus.qt.Qt.from_qvariant`.) .. _Tango: http://www.tango-controls.org/ +.. _Sardana: http://www.sardana-controls.org/ .. _tango_cs: https://sourceforge.net/projects/tango-cs/ .. _reStructuredText: http://docutils.sourceforge.net/rst.html -.. _Sphinx: http://sphinx.pocoo.org/ \ No newline at end of file +.. _Sphinx: http://sphinx.pocoo.org/ diff -Nru taurus-3.0.0/doc/source/devel/color_guide.rst taurus-3.1.0/doc/source/devel/color_guide.rst --- taurus-3.0.0/doc/source/devel/color_guide.rst 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/color_guide.rst 2013-07-25 07:53:11.000000000 +0000 @@ -73,7 +73,7 @@ .ATTR_INVALID { background: rgb(128, 128, 128); color: rgb(255, 255, 255); text-align: right; } .ATTR_VALID { background: rgb(0, 255, 0); color: rgb( 0, 0, 0); text-align: right; } .ATTR_ALARM { background: rgb(255, 140, 0); color: rgb(255, 255, 255); text-align: right; } - .ATTR_WARNING { background: rgb(255, 140, 0); color: rgb(255, 255, 255); text-align: right; } + .ATTR_WARNING { background: rgb(255, 140, 0); color: rgb( 0, 0, 0); text-align: right; } .ATTR_CHANGING { background: rgb(128, 160, 255); color: rgb( 0, 0, 0); text-align: right; } .ATTR_UNKNOWN { background: rgb(128, 128, 128); color: rgb( 0, 0, 0); text-align: right; } .ATTR_NONE { background: rgb(128, 128, 128); color: rgb( 0, 0, 0); text-align: right; } @@ -87,7 +87,7 @@ ATTR_INVALIDGray (128,128,128)White (255,255,255)----- ATTR_VALIDDead Frog Green (0,255,0)Black (0,0,0)10.89 mV ATTR_ALARMOrange (255,140,0)White (255,255,255)76.54 mV - ATTR_WARNINGOrange (255,140,0)White (255,255,255)64.23 mV + ATTR_WARNINGOrange (255,140,0)Black (0,0,0)64.23 mV ATTR_CHANGINGLight Blue (128,160,255)Black (0,0,0)20.45 mV NoneGray (128,128,128)Black (0,0,0)----- diff -Nru taurus-3.0.0/doc/source/devel/examples/edit01.py taurus-3.1.0/doc/source/devel/examples/edit01.py --- taurus-3.0.0/doc/source/devel/examples/edit01.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/edit01.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.application import TaurusApplication app = TaurusApplication(sys.argv) diff -Nru taurus-3.0.0/doc/source/devel/examples/edit02.py taurus-3.1.0/doc/source/devel/examples/edit02.py --- taurus-3.0.0/doc/source/devel/examples/edit02.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/edit02.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.container import TaurusWidget from taurus.qt.qtgui.display import TaurusValueLabel, TaurusConfigLabel from taurus.qt.qtgui.input import TaurusValueSpinBox @@ -28,5 +28,5 @@ w3.setModel('/position') w4.setModel('/position?configuration=unit') -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) \ No newline at end of file diff -Nru taurus-3.0.0/doc/source/devel/examples/edit03.py taurus-3.1.0/doc/source/devel/examples/edit03.py --- taurus-3.0.0/doc/source/devel/examples/edit03.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/edit03.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.container import TaurusWidget from taurus.qt.qtgui.display import TaurusValueLabel, TaurusConfigLabel from taurus.qt.qtgui.input import TaurusWheelEdit @@ -28,5 +28,5 @@ w3.setModel('/position') w4.setModel('/position?configuration=unit') -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) \ No newline at end of file diff -Nru taurus-3.0.0/doc/source/devel/examples/forms01.py taurus-3.1.0/doc/source/devel/examples/forms01.py --- taurus-3.0.0/doc/source/devel/examples/forms01.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/forms01.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.panel import TaurusForm app = Qt.QApplication(sys.argv) @@ -8,5 +8,5 @@ props = [ 'state', 'status', 'position', 'velocity', 'acceleration' ] model = [ 'sys/taurustest/1/%s' % p for p in props ] panel.setModel(model) -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/forms02.py taurus-3.1.0/doc/source/devel/examples/forms02.py --- taurus-3.0.0/doc/source/devel/examples/forms02.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/forms02.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,17 +1,16 @@ import sys -from PyQt4 import Qt from taurus.qt.qtgui.panel import TaurusForm from taurus.qt.qtgui.display import TaurusValueLabel -from taurus.qt.qtgui.input import TaurusWheelEdit +from taurus.qt.qtgui.application import TaurusApplication -app = Qt.QApplication(sys.argv) +app = TaurusApplication(sys.argv) panel = TaurusForm() props = [ 'state', 'status', 'position', 'velocity', 'acceleration' ] model = [ 'sys/taurustest/1/%s' % p for p in props ] panel.setModel(model) -panel.getItemByIndex(0).setReadWidgetClass(TaurusValueLabel) -panel.getItemByIndex(2).setWriteWidgetClass(TaurusWheelEdit) +panel[0].readWidgetClass = TaurusValueLabel +panel[2].writeWidgetClass='TaurusWheelEdit' -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/label01.py taurus-3.1.0/doc/source/devel/examples/label01.py --- taurus-3.0.0/doc/source/devel/examples/label01.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/label01.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.application import TaurusApplication app = TaurusApplication(sys.argv) diff -Nru taurus-3.0.0/doc/source/devel/examples/label02.py taurus-3.1.0/doc/source/devel/examples/label02.py --- taurus-3.0.0/doc/source/devel/examples/label02.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/label02.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.application import TaurusApplication app = TaurusApplication(sys.argv) diff -Nru taurus-3.0.0/doc/source/devel/examples/label03.py taurus-3.1.0/doc/source/devel/examples/label03.py --- taurus-3.0.0/doc/source/devel/examples/label03.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/label03.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.application import TaurusApplication app = TaurusApplication(sys.argv) diff -Nru taurus-3.0.0/doc/source/devel/examples/label04.py taurus-3.1.0/doc/source/devel/examples/label04.py --- taurus-3.0.0/doc/source/devel/examples/label04.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/label04.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.container import TaurusWidget from taurus.qt.qtgui.display import TaurusValueLabel, TaurusConfigLabel @@ -22,6 +22,6 @@ layout.addWidget(w1) layout.addWidget(w2) layout.addWidget(w3) -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/label05.py taurus-3.1.0/doc/source/devel/examples/label05.py --- taurus-3.0.0/doc/source/devel/examples/label05.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/label05.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,11 +1,11 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.display import TaurusStateLabel app = Qt.QApplication(sys.argv) panel = Qt.QWidget() w = TaurusStateLabel(panel) w.setModel('sys/taurustest/1/state') -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/label06.py taurus-3.1.0/doc/source/devel/examples/label06.py --- taurus-3.0.0/doc/source/devel/examples/label06.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/label06.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.display import TaurusStateLabel app = Qt.QApplication(sys.argv) @@ -13,6 +13,6 @@ w.setShowText(False) #w.setShowQualityForeground(False) layout.addWidget(w,x,y) -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/parentmodel_issue_demo.py taurus-3.1.0/doc/source/devel/examples/parentmodel_issue_demo.py --- taurus-3.0.0/doc/source/devel/examples/parentmodel_issue_demo.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/parentmodel_issue_demo.py 2013-07-25 07:53:10.000000000 +0000 @@ -9,7 +9,7 @@ You can do it right after calling the setupUi method. ''' -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.container import TaurusWidget from taurus.qt.qtgui.display import TaurusValueLabel import sys diff -Nru taurus-3.0.0/doc/source/devel/examples/pyqwt_issue_test.py taurus-3.1.0/doc/source/devel/examples/pyqwt_issue_test.py --- taurus-3.0.0/doc/source/devel/examples/pyqwt_issue_test.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/pyqwt_issue_test.py 2013-07-25 07:53:10.000000000 +0000 @@ -5,7 +5,7 @@ If you are affected, the solution is to install/compile a newer version of PyQwt/SIP Notably, the python-qwt5-qt4 package originally shipped with -Ubuntu 10.10 is affected +Ubuntu 10.10 and Debian 6 is affected In some systems, the bug produces a segfault while in some others it produces an Assertion error similar to the following: @@ -19,11 +19,11 @@ from PyQt4 import Qt, Qwt5 class MyScaleDrawSafe(Qwt5.QwtScaleDraw): - def __init__(self, format = None, palette = None): + def __init__(self): Qwt5.QwtScaleDraw.__init__(self) class MyScaleDrawDanger(Qwt5.QwtScaleDraw): - def __init__(self, format = None, palette = None): + def __init__(self): Qwt5.QwtScaleDraw.__init__(self) def label(self, val): @@ -31,7 +31,7 @@ class MyPlot(Qwt5.QwtPlot): - def __init__(self, parent = None, designMode = False): + def __init__(self, parent = None): Qwt5.QwtPlot.__init__(self, parent) self.setAxisScaleDraw(Qwt5.QwtPlot.xBottom, MyScaleDrawSafe()) print "Replotting with MyScaleDrawSafe:..." diff -Nru taurus-3.0.0/doc/source/devel/examples/taurusplot01.py taurus-3.1.0/doc/source/devel/examples/taurusplot01.py --- taurus-3.0.0/doc/source/devel/examples/taurusplot01.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/taurusplot01.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.plot import TaurusPlot app = Qt.QApplication(sys.argv) @@ -16,5 +16,5 @@ ######################## #END EXAMPLE CODE ######################## -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/taurusplot02.py taurus-3.1.0/doc/source/devel/examples/taurusplot02.py --- taurus-3.0.0/doc/source/devel/examples/taurusplot02.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/taurusplot02.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.plot import TaurusPlot app = Qt.QApplication(sys.argv) @@ -16,5 +16,5 @@ ######################## #END EXAMPLE CODE ######################## -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/taurusplot03.py taurus-3.1.0/doc/source/devel/examples/taurusplot03.py --- taurus-3.0.0/doc/source/devel/examples/taurusplot03.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/taurusplot03.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.plot import TaurusPlot, CurveAppearanceProperties app = Qt.QApplication(sys.argv) @@ -10,7 +10,7 @@ ########################## import numpy -from PyQt4 import Qwt5 +from taurus.qt import Qwt5 panel = TaurusPlot() @@ -40,5 +40,5 @@ ######################## #END EXAMPLE CODE ######################## -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/taurustrend01.py taurus-3.1.0/doc/source/devel/examples/taurustrend01.py --- taurus-3.0.0/doc/source/devel/examples/taurustrend01.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/taurustrend01.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/env python import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.plot import TaurusTrend app = Qt.QApplication(sys.argv) @@ -17,5 +17,5 @@ ######################## #END EXAMPLE CODE ######################## -panel.setVisible(True) +panel.show() sys.exit(app.exec_()) diff -Nru taurus-3.0.0/doc/source/devel/examples/taurusvalue01.py taurus-3.1.0/doc/source/devel/examples/taurusvalue01.py --- taurus-3.0.0/doc/source/devel/examples/taurusvalue01.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples/taurusvalue01.py 2013-07-25 07:53:10.000000000 +0000 @@ -1,5 +1,5 @@ import sys -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.application import TaurusApplication from taurus.qt.qtgui.panel import TaurusValue diff -Nru taurus-3.0.0/doc/source/devel/examples.rst taurus-3.1.0/doc/source/devel/examples.rst --- taurus-3.0.0/doc/source/devel/examples.rst 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/examples.rst 2013-07-25 07:53:11.000000000 +0000 @@ -46,7 +46,7 @@ header:: import sys - from PyQt4 import Qt + from taurus.qt import Qt from taurus.qt.qtgui.application import TaurusApplication app = TaurusApplication(sys.argv) @@ -76,7 +76,7 @@ code:: import sys - from PyQt4 import Qt + from taurus.qt import Qt from taurus.qt.qtgui.application import TaurusApplication app = TaurusApplication(sys.argv) @@ -224,8 +224,8 @@ props = [ 'state', 'status', 'position', 'velocity', 'acceleration' ] model = [ 'sys/taurustest/1/%s' % p for p in props ] panel.setModel(model) - panel.getItemByIndex(0).setReadWidgetClass(TaurusLabel) # you can provide an arbitrary class... - panel.getItemByIndex(2).setWriteWidgetClass('TaurusWheelEdit') # ...or, if Taurus knows it, just give its name + panel[0].readWidgetClass = TaurusLabel # you can provide an arbitrary class... + panel[2].writeWidgetClass = 'TaurusWheelEdit' # ...or, if it is a Taurus class you can just give its name *A little configuration goes a long way!* @@ -300,7 +300,7 @@ code:: import numpy - from PyQt4 import Qwt5 + from taurus.qt import Qwt5 from taurus.qt.qtgui.plot import TaurusPlot, CurveAppearanceProperties panel = TaurusPlot() diff -Nru taurus-3.0.0/doc/source/devel/icon_example.py taurus-3.1.0/doc/source/devel/icon_example.py --- taurus-3.0.0/doc/source/devel/icon_example.py 2012-04-30 07:46:12.000000000 +0000 +++ taurus-3.1.0/doc/source/devel/icon_example.py 2013-07-25 07:53:11.000000000 +0000 @@ -1,4 +1,4 @@ -from PyQt4 import Qt +from taurus.qt import Qt from taurus.qt.qtgui.resource import getThemeIcon class MyGUI(Qt.QMainWindow): diff -Nru taurus-3.0.0/doc/source/index.rst taurus-3.1.0/doc/source/index.rst --- taurus-3.0.0/doc/source/index.rst 2012-04-30 07:46:22.000000000 +0000 +++ taurus-3.1.0/doc/source/index.rst 2013-07-25 07:53:14.000000000 +0000 @@ -10,15 +10,16 @@ .. sidebar:: Latest news + + 2013-07-25 + Taurus 3.1.0 released! + 2012-04-24 Taurus 3.0.0 released! 2011-03-23 Taurus 2.1.1 released! - 2011-03-22: - Taurus 2.1.0 released! - Taurus is a python framework for both CLI and GUI tango applications. It is build on top of PyTango_ and PyQt_. Taurus stands for TAngo User interface 'R' US. diff -Nru taurus-3.0.0/doc/source/users/getting_started.rst taurus-3.1.0/doc/source/users/getting_started.rst --- taurus-3.0.0/doc/source/users/getting_started.rst 2012-04-30 07:46:13.000000000 +0000 +++ taurus-3.1.0/doc/source/users/getting_started.rst 2013-07-25 07:53:11.000000000 +0000 @@ -10,8 +10,21 @@ Installing ---------- -Linux -~~~~~ +Linux (Debian-based) +~~~~~~~~~~~~~~~~~~~~ + +Since v3.0, Taurus is part of the official repositories of Debian (and Ubuntu +and other Debian-based distros). You can install it and all its dependencies by +doing (as root):: + + aptitude install python-taurus + +(see more detailed instructions in `this step-by-step howto +`__) + + +Linux (generic) +~~~~~~~~~~~~~~~ #. Download the latest version of taurus from http://pypi.python.org/pypi/taurus #. Extract the downloaded tar.gz into a temporary directory @@ -56,9 +69,13 @@ Working from SVN ---------------- +.. warning:: These instructions will become obsolete as soon as Taurus 3.1 + is released because the code development will be moved from SVN to + Git. Updated instructions for using Git will be posted ASAP. + You can checkout taurus from SVN from the following location:: - svn co http://tango-cs.svn.sourceforge.net/svnroot/tango-cs/gui/taurus/trunk taurus + svn co https://svn.code.sf.net/p/tango-cs/code/gui/taurus/trunk taurus taurus Afterward, if you decide to work directly from SVN code (without installing): @@ -135,18 +152,17 @@ python -c 'import PyQt4.Qwt5; print PyQt4.Qwt5.QWT_VERSION_STR' -- The image widgets are only available if you have Qub_. Qub_ is a graphical - library provided by the BLISS group in ESRF_. - You may already have Qub_ installed. You will need Qub for qt4. - You can check it by doing:: - - python -c 'import Qub' +- The image widgets are provided by the guiqwt_ library. The widgets based on + this library replace the previously used Qub_-based image widget which is now + considered deprecated in Taurus - The Gauge widgets are only available if you have the python extension of qtcontrols. qtcontrols is part of QTango_. - The JDraw synoptics widgets are only available if you have the :mod:`ply` package installed. + +- The NeXus browser widget is only available if you have PyMca_ installed .. _numpy: http://numpy.scipy.org/ @@ -159,6 +175,7 @@ .. _Qt: http://qt.nokia.com/products/ .. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/ .. _PyQwt: http://pyqwt.sourceforge.net/ +.. _guiqwt: http://code.google.com/p/guiqwt/ .. _IPython: http://ipython.scipy.org/ .. _Qub: http://www.blissgarden.org/projects/qub/ -.. _ESRF: http://www.esrf.eu/ +.. _PyMca: http://pymca.sourceforge.net/ diff -Nru taurus-3.0.0/doc/source/users/introduction.rst taurus-3.1.0/doc/source/users/introduction.rst --- taurus-3.0.0/doc/source/users/introduction.rst 2012-04-30 07:46:13.000000000 +0000 +++ taurus-3.1.0/doc/source/users/introduction.rst 2013-07-25 07:53:11.000000000 +0000 @@ -4,16 +4,31 @@ Introduction ============ -taurus is a library for connecting client side applications (CLIs and GUIs) to -Tango_ device servers. It is built on top of PyTango_ which is a python binding -for the Tango_ library. It provides an abstraction layer that allows Tango to -be accessed in a pythonic, object oriented way. For the GUI part, taurus is built +taurus was originally conceived as a library for connecting client side +applications (CLIs and GUIs) to Tango_ device servers. + +.. note:: More recently, the scope of Taurus + has been broadened and it is moving towards supporting pluggins for + other control systems (e.g. Epics_, Spec_...). While many concepts of + Taurus Design are heavily influenced by the Tango philosophy, the goal + is to eventually provide a control-system agnostic API allowing + different control systems to be used even simultaneously. + Nevertheless, due to its Tango roots, this documentation may assume + that you are using Tango. + +Taurus is developed as a part of the Sardana_ project, which aims to provide an +integrated SCADA, but it can be used independently of the rest of Sardana. + +For its Tango interface, Taurus uses PyTango_ which is a python binding +for the Tango_ library. It provides an abstraction layer that allows Tango to be +accessed in a pythonic, object oriented way. For the GUI part, taurus is built on top of the graphical library PyQt_ which is a python binding for Qt_. The goals of this library are: - - provide a simple Tango API to the end-user application - - speed up development of tango based applications + - provide a simple Tango (and other control systems) API to the end-user application + - speed up development of tango (and other control systems) based applications - provide a standardized look-and-feel + For example, to display the values of four attributes (state, position, velocity, acceleration) of a device (motor/icepap/01):: @@ -51,7 +66,7 @@ Tango_/PyTango_ and Qt_/PyQt_. Although taurus is written primarily in pure python, it makes heavy use of -PyTango_, numpy_, Qub_, PyQt_ and PyQwt_ to provide good performance even when +PyTango_, numpy_, PyQt_ and PyQwt_ to provide good performance even when large amounts of data are involved. taurus is designed with the philosophy that you should be able to create simple @@ -67,12 +82,16 @@ :scale: 80 :align: center -The taurus library is divided into two parts: the core module which handles all -interaction with PyTango_ (:ref:`taurus-core-tutorial`) and the widget module which -provides a collection of widgets that can be used inside any PyQt_ based GUI -(:ref:`taurus-widget-tutorial`). +The taurus library provides a core module that does not depend on PyQt and which +is in charge of abstracting the lower level comunication with the control system +(:ref:`taurus-core-tutorial`). On top of the core, the qt module provides a +collection of widgets that can be used inside any PyQt_ based GUI +(:ref:`examples`). Recently, the proof-of-concept web module is being +implemented for providing web widgets. +.. _Sardana: http://www.sardana-controls.org/ .. _Tango: http://www.tango-controls.org/ +.. _Epics: http://www.aps.anl.gov/epics/ .. _PyTango: http://packages.python.org/PyTango/ .. _QTango: http://www.tango-controls.org/download/index_html#qtango3 .. _`PyTango installation steps`: http://packages.python.org/PyTango/start.html#getting-started diff -Nru taurus-3.0.0/doc/source/users/ui/experimentconfiguration.rst taurus-3.1.0/doc/source/users/ui/experimentconfiguration.rst --- taurus-3.0.0/doc/source/users/ui/experimentconfiguration.rst 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/doc/source/users/ui/experimentconfiguration.rst 2013-07-25 07:53:11.000000000 +0000 @@ -0,0 +1,15 @@ +.. currentmodule:: taurus.qt.qtgui.extra_sardana + +.. _expconf_ui: + + +======================================= +Experiment Configuration user interface +======================================= + +.. contents:: + +.. todo:: + Experiment Configuration documentation to be written + + \ No newline at end of file diff -Nru taurus-3.0.0/doc/source/users/ui/index.rst taurus-3.1.0/doc/source/users/ui/index.rst --- taurus-3.0.0/doc/source/users/ui/index.rst 2012-04-30 07:46:13.000000000 +0000 +++ taurus-3.1.0/doc/source/users/ui/index.rst 2013-07-25 07:53:11.000000000 +0000 @@ -19,6 +19,9 @@ Synoptics Macros TaurusGui + Experiment Configuration + Sardana Editor + This section explains some features that are common to most applications built diff -Nru taurus-3.0.0/doc/source/users/ui/sardanaeditor.rst taurus-3.1.0/doc/source/users/ui/sardanaeditor.rst --- taurus-3.0.0/doc/source/users/ui/sardanaeditor.rst 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/doc/source/users/ui/sardanaeditor.rst 2013-07-25 07:53:11.000000000 +0000 @@ -0,0 +1,15 @@ +.. currentmodule:: taurus.qt.qtgui.extra_sardana + +.. _sardanaeditor_ui: + + +========================== +Sardana Editor's interface +========================== + +.. contents:: + +.. todo:: + Sardana Editor documentation to be written + + \ No newline at end of file diff -Nru taurus-3.0.0/doc/source/users/ui/taurusgui.rst taurus-3.1.0/doc/source/users/ui/taurusgui.rst --- taurus-3.0.0/doc/source/users/ui/taurusgui.rst 2012-04-30 07:46:13.000000000 +0000 +++ taurus-3.1.0/doc/source/users/ui/taurusgui.rst 2013-07-25 07:53:11.000000000 +0000 @@ -207,8 +207,8 @@ down button in the perspectives toolbar (or using the `View->Load perspective` option). -Apart from the pre-defined perspectives, you can always alter the panel re- -arrange panels and store your preferred arrangement as a perspective using the +Apart from the pre-defined perspectives, you can always re-arrange panels and +store your preferred arrangement as a perspective using the `Save perspective` button in the perspectives toolbar (or using the `View->Save perspective` option). @@ -254,12 +254,17 @@ - `Macros`, :ref:`a macro executor ` widget. See :ref:`this ` for further information. - `Sequences`, :ref:`a macro sequencer ` widget. See :ref:`this ` for further information. -- `1D Scans`, :ref:`a trend ` that plots the results of scan macro executions. - `MacroDescription`, a text panel which provides documentation on the selected macro. - `DoorOutput`, a text panel that logs the output of macro executions (similar to what you would see if launching the macro in a `spock` console) - `DoorDebug`, a text panel that logs the debug messages of macro executions. - `DoorResult`, a text panel that logs the return value of the macro executions. +- `Experiment Config`, `an experiment configuration ` widget for configuring acquisition and display parameters +- `Sardana Editor`, `a Sardana-aware code editor ` for creating/modifying Sardana macros. + +Also, some other temporary panels may be dynamically created depending on the experiment configuration: + +- `1D Scans`, :ref:`a trend ` that plots the values of scalar attributes during some scan macro executions. .. note:: You can run `taurusgui macrogui` for seeing an example of a TaurusGUI- based application that provides the aforementioned panels diff -Nru taurus-3.0.0/lib/taurus/TaurusCustomSettings.py taurus-3.1.0/lib/taurus/TaurusCustomSettings.py --- taurus-3.0.0/lib/taurus/TaurusCustomSettings.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/TaurusCustomSettings.py 2013-07-25 07:53:44.000000000 +0000 @@ -24,25 +24,6 @@ ############################################################################# """ -This module contains some Taurus-wide default configurations. - -The idea is that the final user may edit the values here to customize certain -aspects of Taurus. +Deprecation Note: This module has been renamed to "tauruscustomsettings.py """ - -# A map for using custom widgets for certain devices in TaurusForms. It is a -# dictionary with the following structure: -# device_class_name:(classname_with_full_module_path, args, kwargs) -# where the args and kwargs will be passed to the constructor of the class -T_FORM_CUSTOM_WIDGET_MAP = \ - {'SimuMotor':('taurus.qt.qtgui.extra_pool.PoolMotorTV',(),{}), - 'Motor':('taurus.qt.qtgui.extra_pool.PoolMotorTV',(),{}), - 'PseudoMotor':('taurus.qt.qtgui.extra_pool.PoolMotorTV',(),{}), - 'PseudoCounter':('taurus.qt.qtgui.extra_pool.PoolChannelTV',(),{}), - 'CTExpChannel':('taurus.qt.qtgui.extra_pool.PoolChannelTV',(),{}), - 'ZeroDExpChannel':('taurus.qt.qtgui.extra_pool.PoolChannelTV',(),{}), - 'OneDExpChannel':('taurus.qt.qtgui.extra_pool.PoolChannelTV',(),{}), - 'TwoDExpChannel':('taurus.qt.qtgui.extra_pool.PoolChannelTV',(),{}), - 'IORegister':('taurus.qt.qtgui.extra_pool.PoolIORegisterTV',(),{}) - } - +raise DeprecationWarning('"TaurusCustomSettings" module has been renamed. Use "tauruscustomsettings" instead') diff -Nru taurus-3.0.0/lib/taurus/__init__.py taurus-3.1.0/lib/taurus/__init__.py --- taurus-3.0.0/lib/taurus/__init__.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/__init__.py 2013-07-25 07:53:44.000000000 +0000 @@ -26,7 +26,7 @@ """The main taurus module. It contains a reduced set of wrappers around the real taurus model classes and information regarding the current release.""" -from .core import Release as __R +from .core import release as __R class Release: pass diff -Nru taurus-3.0.0/lib/taurus/console/enums.py taurus-3.1.0/lib/taurus/console/enums.py --- taurus-3.0.0/lib/taurus/console/enums.py 2012-04-30 07:46:23.000000000 +0000 +++ taurus-3.1.0/lib/taurus/console/enums.py 2013-07-25 07:53:14.000000000 +0000 @@ -29,7 +29,7 @@ __docformat__ = "restructuredtext" -from taurus.core.util import Enumeration +from taurus.core.util.enumeration import Enumeration #: Flaggable alignment for both horizontal and vertical text #: Conflicting combinations of flags have undefined meanings. diff -Nru taurus-3.0.0/lib/taurus/core/__init__.py taurus-3.1.0/lib/taurus/core/__init__.py --- taurus-3.0.0/lib/taurus/core/__init__.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/__init__.py 2013-07-25 07:53:43.000000000 +0000 @@ -27,25 +27,11 @@ __docformat__ = "restructuredtext" -import release as Release -from .enums import * -from .taurusbasetypes import * -from .taurusexception import * -from .taurusmodel import * -from .tauruslistener import * -from .taurusdevice import * -from .taurusattribute import * -from .taurusconfiguration import * -from .taurusdatabase import * -from .taurusfactory import * -from .taurusmanager import * -from .taurusoperation import * -from .tauruspollingtimer import * -from .taurusvalidator import * +import taurus.tauruscustomsettings -# enable compatibility code with tau V1 if tauv1 package is present -try: - from .tauv1 import * -except: - pass +LIGHTWEIGHT_IMPORTS = getattr(taurus.tauruscustomsettings, 'LIGHTWEIGHT_IMPORTS', False) +if LIGHTWEIGHT_IMPORTS: + from init_lightweight import * +else: + from init_bkcomp import * \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/core/enums.py taurus-3.1.0/lib/taurus/core/enums.py --- taurus-3.0.0/lib/taurus/core/enums.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/enums.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,172 +0,0 @@ -#!/usr/bin/env python - -############################################################################# -## -## This file is part of Taurus, a Tango User Interface Library -## -## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html -## -## 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 . -## -############################################################################# - -"""This module contains all basic taurus enumerations""" - -__all__ = ["TaurusSWDevState", "TaurusSWDevHealth", "OperationMode", - "TaurusSerializationMode", "SubscriptionState", "TaurusEventType", - "MatchLevel", "TaurusElementType", "LockStatus", "DataFormat", - "AttrQuality", "AttrAccess", "DisplayLevel", "ManagerState"] - -__docformat__ = "restructuredtext" - -import util - -TaurusSWDevState = util.Enumeration( -'TaurusSWDevState', ( - 'Uninitialized', - 'Running', - 'Shutdown', - 'Crash', - 'EventSystemShutdown' -)) - -TaurusSWDevHealth = util.Enumeration( -'TaurusSWDevHealth', ( - 'Exported', # device reported exported - 'ExportedAlive', # device reported exported and confirmed connection - 'ExportedNotAlive', # device reported exported but connection failed!! - 'NotExported', # device didn't report exported - 'NotExportedAlive', # device didn't report exported but connection confirmed! - 'NotExportedNotAlive' # device didn't report exported and connection failed -)) - -OperationMode = util.Enumeration( -'OperationMode', ( - 'OFFLINE', - 'ONLINE' -)) - -TaurusSerializationMode = util.Enumeration( -'TaurusSerializationMode', ( - 'Serial', - 'Concurrent' -)) - -TaurusEventType = util.Enumeration( -'TaurusEventType', ( - 'Change', - 'Config', - 'Periodic', - 'Error' -)) - -MatchLevel = util.Enumeration( -'MatchLevel', ( - 'ANY', - 'SHORT', - 'NORMAL', - 'COMPLETE', - 'SHORT_NORMAL', - 'NORMAL_COMPLETE' -)) - -TaurusElementType = util.Enumeration( -'TaurusElementType', ( - 'Unknown', - 'Name', - 'DeviceClass', - 'Device', - 'DeviceAlias', - 'Domain', - 'Family', - 'Member', - 'Server', - 'ServerName', - 'ServerInstance', - 'Exported', - 'Host', - 'Attribute', - 'AttributeAlias', - 'Command', - 'Property', - 'Configuration', - 'Database', -)) - -LockStatus = util.Enumeration( -'LockStatus', ( - 'Unlocked', - 'Locked', - 'LockedMaster', - 'Unknown', -)) - -DataFormat = util.Enumeration( -'DataFormat', ( - '_0D', - '_1D', - '_2D' -)) - -DataType = util.Enumeration( -'DataType', ( - 'Integer', - 'Float', - 'String', - 'Boolean', -)) - -SubscriptionState = util.Enumeration( -"SubscriptionState", ( - "Unsubscribed", - "Subscribing", - "Subscribed", - "PendingSubscribe" -)) - -################# -# Not in use yet: - -AttrQuality = util.Enumeration( -'AttrQuality', ( - 'ATTR_VALID', - 'ATTR_INVALID', - 'ATTR_ALARM' -)) - -AttrAccess = util.Enumeration( -'AttrAccess', ( - 'READ', - 'READ_WITH_WRITE', - 'WRITE', - 'READ_WRITE' -)) - -DisplayLevel = util.Enumeration( -'DisplayLevel', ( - 'OPERATOR', - 'EXPERT', - 'DEVELOPER' -)) - -ManagerState = util.Enumeration( -'ManagerState', ( - 'UNINITIALIZED', - 'INITED', - 'CLEANED' -)) - - diff -Nru taurus-3.0.0/lib/taurus/core/epics/__init__.py taurus-3.1.0/lib/taurus/core/epics/__init__.py --- taurus-3.0.0/lib/taurus/core/epics/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/epics/__init__.py 2013-07-25 07:53:42.000000000 +0000 @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +""" +.. currentmodule:: taurus.core.epics + +Epics extension for taurus core model. + +The epics extension provides access to Epics control system objects + +.. note:: The Epics scheme is only a proof of concept. The final syntax of the models is + not yet set in stone and only basic functionality is implemented. + + +The Epics extension implements :mod:`taurus.core` objects that connect to Epics +objects. The scheme prefix for epics objects is 'epics://'. + +You should never create objects of epics classes directly. Instead you +should use the :class:`taurus.core.taurusmanager.TaurusManager` and +:class:`taurus.core.taurusmanager.TaurusFactory` APIs to access all elements. + +For example, to get a reference to the epics process variable (PV) "my:example.RBV" you +should do something like:: + + >>> import taurus + >>> myattr = taurus.Attribute('epics://my:example.RBV') + +Epics attributes (should) work just as other Taurus attributes and can be +referred by their model name wherever a Taurus Attribute model is expected. For +example, you can launch a `TaurusForm` with an epics attribute:: + + $> taurusform epics://my:example.RBV + +Similarly, you can combine epics attributes with attributes from other schemes:: + + $> taurusform 'epics://my:example.RBV' 'tango://sys/tg_test/1/float_scalar'\ + 'eval://{epics://my:example.RBV}*{tango://sys/tg_test/1/float_scalar}' + +Currently, the taurus epics scheme just supports epics PVs, implementing them as +taurus attributes (with configuration objects as well). Other taurus classes +such as the Database, and Device classes are just convenience dummy objects in +the epics scheme at this point. Epics records may eventually be mapped as +Devices. + +""" + +from epicsfactory import * diff -Nru taurus-3.0.0/lib/taurus/core/epics/epicsfactory.py taurus-3.1.0/lib/taurus/core/epics/epicsfactory.py --- taurus-3.0.0/lib/taurus/core/epics/epicsfactory.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/epics/epicsfactory.py 2013-07-25 07:53:42.000000000 +0000 @@ -0,0 +1,738 @@ +#!/usr/bin/env python +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +''' +Epics module. See __init__.py for more detailed documentation +''' +__all__ = ['EpicsFactory', 'EpicsDatabase', 'EpicsDevice', + 'EpicsAttribute','EpicsConfiguration', + 'EpicsConfigurationNameValidator', 'EpicsDeviceNameValidator', + 'EpicsAttributeNameValidator'] + + + +import time, re, weakref +import numpy + +from taurus import Factory +from taurus.core.taurusexception import TaurusException, DoubleRegistration +from taurus.core.util.singleton import Singleton +from taurus.core.util.log import Logger +from taurus.core.taurusbasetypes import MatchLevel, TaurusSWDevState, \ + SubscriptionState, TaurusEventType, TaurusAttrValue, TaurusTimeVal, \ + AttrQuality +from taurus.core.taurusfactory import TaurusFactory +from taurus.core.taurusattribute import TaurusAttribute +from taurus.core.taurusdevice import TaurusDevice +from taurus.core.taurusdatabase import TaurusDatabase +from taurus.core.taurusconfiguration import TaurusConfiguration +from taurus.core.tauruspollingtimer import TaurusPollingTimer + +try: + import epics +except ImportError: #note that if epics is not installed the factory will not be available + from taurus.core.util.log import debug + debug('cannot import epics module. Taurus will not support the "epics" scheme') + #raise + +class AbstractEpicsNameValidator(Singleton): + #@todo: provide a mechanism to make base_sep configurable at installation time. + base_sep = ':' #the following characters need to be escaped with "\": ^$()<>[{\|.*+? + name_pattern = '' + + def __init__(self): + """ Initialization. Nothing to be done here for now.""" + pass + + def init(self, *args, **kwargs): + """Singleton instance initialization.""" + self.name_re = re.compile(self.name_pattern) + + def isValid(self,s, matchLevel = MatchLevel.ANY): + return self.name_re.match(s) is not None + + def getParams(self, s): + m = self.attrname_re.match(s) + if m is None: + return None + return m.groupdict() + + def getNames(self, s, factory=None): + """Returns the full, normal and simple names for this object, or None if there is no match''' + """ + raise RuntimeError('Not Allowed to call this method from subclasses') + + def getDeviceName(self, s, full=True): + ''' + returns the device name for the given attribute name. + The "full" argument is ignored since the DB is never included in the epics models + ''' + m = self.name_re.match(s) + if m is None: + return None + devname = m.group('devname') or EpicsFactory.DEFAULT_DEVICE + return 'epics://%s%s'%(devname,m.group('base_sep') or self.base_sep ) + + def getDBName(self, s): + '''returns the full data base name for the given attribute name. + Note: the DB name is not a valid epics URI because the epics scheme does not implement a DB model''' + dbname = EpicsFactory.DEFAULT_DATABASE + return dbname + + +class EpicsAttributeNameValidator(AbstractEpicsNameValidator): + #The groups in a match object using the regexp below are: + # 1: scheme; named as 'scheme' + # 2: EPICS PV name (in the case of attribute names) or same as $3 (in the case of device names) + # 3: device name including the trailing base_sep; optional + # 4: device name; optional; named as 'devname' + # 5: base separator if it appears on the URI; named as 'base_sep' + # 6: attribute name;optional; named as 'attrname' + # + # Reconstructing the names + # attrname= $6 + # devname= $4 or EpicsFactory.DEFAULT_DEVICE + # fullname= "epics://%s"%($2) + # + # 1 2 34 5 6 + name_pattern = '^(?Pepics)://(?P((?P[^?#]*)(?P%s))?(?P[^?#%s]+))$'%(AbstractEpicsNameValidator.base_sep, AbstractEpicsNameValidator.base_sep) + +# def isValid(self,s, matchLevel = MatchLevel.ANY): +# m = self.name_re.match(s) +# return m is not None and m.group('attrname') #the model contains an attrname + + def getNames(self, s, factory=None): + """Returns the complete, normal and short names. + + For example:: + + >>> EpicsDeviceNameValidator.getNames("epics://foo:bar:baz") + >>> ("epics://foo:bar:baz", "foo:bar:baz", "baz") + + """ + m = self.name_re.match(s) + if m is None: + return None + #The following comments are for an example name like: "epics://foo:bar:baz" + attr_name = m.group('attrname') # attr_name = "baz" + normal_name = m.group('epicsname') #normal_name = "foo:bar:baz" + fullname = "%s://%s"%(m.group('scheme'),normal_name) #fullname = "epics://foo:bar:baz" + return fullname, normal_name, attr_name + + +class EpicsDeviceNameValidator(AbstractEpicsNameValidator): + '''A validator of names for :class:`EpicsDevice`. By taurusconvention, + the model name for an epics device name *must* end with the base separator + (in order to distinguish device names from attribute names)''' + + name_pattern = '^(?Pepics)://(?P((?P[^?#]*)(?P%s)))$'%(AbstractEpicsNameValidator.base_sep) + +# def isValid(self,s, matchLevel = MatchLevel.ANY): +# m = self.name_re.match(s) +# return m is not None and not m.group('attrname') #to be a device it must not contain an attribute + + def getNames(self, s, factory=None): + """Returns the complete, normal and short names. (note: complete=normal) + + :param s: (str) input string describing the device + :param factory: (TaurusFactory) [Unused] + + :return: (tuple or None) A tuple of complete, normal and + short names, or None if s is an invalid device name + """ + m = self.name_re.match(s) + if m is None: + return None + #The following comments are for a name of the type: "epics://foo:bar:" + devname = m.group('devname') # foo:bar + normal_name = m.group('epicsname') #foo:bar: + full_name = self.getDeviceName(s, full=True) #epics://foo:bar: + return full_name, normal_name, devname + + +class EpicsConfigurationNameValidator(AbstractEpicsNameValidator): + '''A validator of names for :class:`EpicsConfiguration`''' + # The groups in a match object using the regexp below are the + # same as for the AbstractEpicsNameValidator plus: + # +1: configuration extension + # +2: configuration key;optional; named as 'cfgkey' + + name_pattern = '^(?Pepics)://(?P((?P[^?#]*)(?P%s))?(?P[^?#%s]+)\?configuration=?(?P[^#?]*))$'%(AbstractEpicsNameValidator.base_sep, AbstractEpicsNameValidator.base_sep) + + def getNames(self, s, factory=None): + """Returns the complete, normal and short names""" + m = self.name_re.match(s) + if m is None: + return None + #The following comments are for an example name like: "epics://foo:bar:baz?configuration=label" + cfg_key = m.group('cfgkey') # cfg_key = "label" + full_name = s # "epics://foo:bar:baz?configuration=label" + normal_name = full_name # "epics://foo:bar:baz?configuration=label" + return full_name, normal_name, cfg_key + + def getAttrName(self, s): + names = self.getNames(s) + if names is None: return None + return names[0].rsplit('?configuration')[0]#remove the "?configuration..." substring from the fullname + + +class EpicsDatabase(TaurusDatabase): + ''' + Dummy database class for Epics (the Database concept is not used in the Epics scheme) + + .. warning:: In most cases this class should not be instantiated directly. + Instead it should be done via the :meth:`EpicsFactory.getDataBase` + ''' + def factory(self): + return EpicsFactory() + + def __getattr__(self, name): + return "EpicsDatabase object calling %s" % name + + +class EpicsDevice(TaurusDevice): + ''' + An Epics device object. + @todo: For the moment is a dummy object. Eventually we may map it to an epics record. + + .. seealso:: :mod:`taurus.core.epics` + + .. warning:: In most cases this class should not be instantiated directly. + Instead it should be done via the :meth:`EpicsFactory.getDevice` + ''' + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # TaurusModel necessary overwrite + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # helper class property that stores a reference to the corresponding factory + _factory = None + + @classmethod + def factory(cls): + if cls._factory is None: + cls._factory = Factory(scheme='epics') + return cls._factory + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # TaurusDevice necessary overwrite + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + def _createHWObject(self): + return 'Epics' + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + def getAttribute(self, attrname): + """Returns the attribute object given its name""" + full_attrname = "%s%s"%(self.getFullName(), attrname) + return self.factory().getAttribute(full_attrname) + + @classmethod + def getNameValidator(cls): + return EpicsDeviceNameValidator() + + def decode(self, event_value): + if isinstance(event_value, int): # TaurusSWDevState + new_sw_state = event_value + else: + self.info("Unexpected value to decode: %s" % str(event_value)) + new_sw_state = TaurusSWDevState.Crash + value = TaurusAttrValue() + value.value = new_sw_state + return value + + +class EpicsAttribute(TaurusAttribute): + ''' + A :class:`TaurusAttribute` that gives access to an Epics Process Variable. + + .. seealso:: :mod:`taurus.core.epics` + + .. warning:: In most cases this class should not be instantiated directly. + Instead it should be done via the :meth:`EpicsFactory.getAttribute` + ''' + + def __init__(self, name, parent, storeCallback = None): + self.call__init__(TaurusAttribute, name, parent, storeCallback=storeCallback) + + self.__attr_config = None + self.__pv = epics.PV(self.getNormalName(), callback=self.onEpicsEvent) + connected = self.__pv.wait_for_connection() + if connected: + self.info('successfully connected to epics PV') + self._value = self.decode_pv(self.__pv) + else: + self.info('connection to epics PV failed') + self._value = TaurusAttrValue() + + #print "INIT",self.__pv, connected + + def onEpicsEvent(self, **kw): + '''callback for PV changes''' + self._value = self.decode_epics_evt(kw) + self.fireEvent(TaurusEventType.Change, self._value) + + def __getattr__(self,name): + return getattr(self._getRealConfig(), name) + + def _getRealConfig(self): + """ Returns the current configuration of the attribute.""" + if self.__attr_config is None: + cfg_name = "%s?configuration" % self.getFullName() + self.__attr_config = EpicsConfiguration(cfg_name, self) + return self.__attr_config + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # Necessary to overwrite from TaurusAttribute + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + def isNumeric(self): + return True + + def isBoolean(self): + return isinstance(self._value.value, bool) + + def isState(self): + return False + + def getDisplayValue(self,cache=True): + return self.__pv.get(as_string=True, use_monitor=cache) + + def encode(self, value): + '''encodes the value passed to the write method into + a representation that can be written in epics''' + try: + typeclass = numpy.dtype(self.__pv.type).type + return typeclass(value) #cast the value with the python type for this PV + except: + return value + + def decode (self, obj): + if isinstance(obj, epics.PV): + return self.decode_pv(obj) + else: + return self.decode_epics_evt(obj) + + def decode_pv(self, pv): + """Decodes an epics pv into the expected taurus representation""" + #@todo: This is a very basic implementation, and things like quality may not be correct + attr_value = TaurusAttrValue() + attr_value.value = pv.value + if pv.write_access: + attr_value.w_value = pv.value + if pv.timestamp is None: + attr_value.time = TaurusTimeVal.now() + else: + attr_value.time = TaurusTimeVal.fromtimestamp(pv.timestamp) + if pv.severity > 0: + attr_value.quality = AttrQuality.ATTR_ALARM + else: + attr_value.quality = AttrQuality.ATTR_VALID + attr_value.config.data_format = len(numpy.shape(attr_value.value)) + return attr_value + + def decode_epics_evt(self, evt): + """Decodes an epics event (a callback keywords dict) into the expected taurus representation""" + #@todo: This is a very basic implementation, and things like quality may not be correct + attr_value = TaurusAttrValue() + attr_value.value = evt.get('value') + if evt.get('write_access', False): + attr_value.w_value = attr_value.value + timestamp = evt.get('timestamp', None) + if timestamp is None: + attr_value.time = TaurusTimeVal.now() + else: + attr_value.time = TaurusTimeVal.fromtimestamp(timestamp) + if evt.get('severity', 1) > 0: + attr_value.quality = AttrQuality.ATTR_ALARM + else: + attr_value.quality = AttrQuality.ATTR_VALID + attr_value.config.data_format = len(numpy.shape(attr_value.value)) + return attr_value + + def write(self, value, with_read=True): + value = self.encode(value) + self.__pv.put(value) + if with_read: + return self.decode_pv(self.__pv) + + def read(self, cache=True): + '''returns the value of the attribute. + + :param cache: (bool) If True (default), the last calculated value will + be returned. If False, the referenced values will be re- + read and the transformation string will be re-evaluated + + :return: attribute value + ''' + if not cache: + self.__pv.get(use_monitor=False) + self._value = self.decode_pv(self.__pv) + return self._value + + def poll(self): + v = self.read(cache=False) + self.fireEvent(TaurusEventType.Periodic, v) + + def isUsingEvents(self): + return True #@todo + +#------------------------------------------------------------------------------ + + def isWritable(self, cache=True): + return self.__pv.write_access + + def isWrite(self, cache=True): + return self.__pv.write_access + + def isReadOnly(self, cache=True): + return self.__pv.read_access and not self.__pv.write_access + + def isReadWrite(self, cache=True): + return self.__pv.read_access and self.__pv.write_access + + def getWritable(self, cache=True): + return self.__pv.write_access + + + def factory(self): + return EpicsFactory() + + @classmethod + def getNameValidator(cls): + return EpicsAttributeNameValidator() + + + +class EpicsConfiguration(TaurusConfiguration): + ''' + A :class:`TaurusConfiguration` + + .. seealso:: :mod:`taurus.core.epics` + + .. warning:: In most cases this class should not be instantiated directly. + Instead it should be done via the :meth:`EpicsFactory.getConfig` + ''' + def __init__(self, name, parent, storeCallback = None): + self.call__init__(TaurusConfiguration, name, parent, storeCallback=storeCallback) + + #fill the attr info + i = parent.read().config + a=parent + d=self._getDev() + # add dev_name, dev_alias, attr_name, attr_full_name + i.dev_name = d.getNormalName() + i.dev_alias = d.getSimpleName() + i.attr_name = a.getSimpleName() + i.attr_fullname = a.getNormalName() + i.label = a.getSimpleName() + self._attr_info = i + + def __getattr__(self, name): + try: + return getattr(self._attr_info,name) + except: + raise AttributeError("'%s'object has no attribute '%s'"%(self.__class__.__name__, name)) + @classmethod + def getNameValidator(cls): + return EpicsConfigurationNameValidator() + + def _subscribeEvents(self): + pass + + def _unSubscribeEvents(self): + pass + + def factory(self): + EpicsFactory() + + def getValueObj(self, cache=True): + """ Returns the current configuration for the attribute.""" + return self._attr_info + + +class EpicsFactory(Singleton, TaurusFactory, Logger): + """ + A Singleton class that provides Epics related objects. + """ + + schemes = ("epics",) + DEFAULT_DEVICE = '_DefaultEpicsDevice' + DEFAULT_DATABASE = '_DefaultEpicslDB' + def __init__(self): + """ Initialization. Nothing to be done here for now.""" + pass + + def init(self, *args, **kwargs): + """Singleton instance initialization.""" + name = self.__class__.__name__ + self.call__init__(Logger, name) + self.call__init__(TaurusFactory) + self.epics_attrs = weakref.WeakValueDictionary() + self.epics_devs = weakref.WeakValueDictionary() + self.epics_configs = weakref.WeakValueDictionary() + + def findObjectClass(self, absolute_name): + """ + Obtain the class object corresponding to the given name. + """ + if EpicsConfiguration.isValid(absolute_name): + return EpicsConfiguration + elif EpicsDevice.isValid(absolute_name): + return EpicsDevice + elif EpicsAttribute.isValid(absolute_name): + return EpicsAttribute + else: + self.debug("Not able to find Object class for %s" % absolute_name) + self.traceback() + return None + + def getDatabase(self, db_name=None): + """Obtain the EpicsDatabase object. + + :param db_name: (str) this is ignored because only one dummy database is supported + + :return: (EpicsDatabase) + """ + if not hasattr(self, "_db"): + self._db = EpicsDatabase(self.DEFAULT_DATABASE) + return self._db + + def getDevice(self, dev_name): + """Obtain the EpicsDevice object. + + :param dev_name: (str) this is ignored because only one dummy device is supported + + :return: (EpicsDevice) + + .. todo:: Epics records may be implemented as taurus devices... + """ + d = self.epics_devs.get(dev_name, None) #first try with the given name + if d is None: #if not, try with the full name + validator = EpicsDevice.getNameValidator() + names = validator.getNames(dev_name) + if names is None: + raise TaurusException("Invalid epics device name %s" % dev_name) + fullname = names[0] + d = self.epics_devs.get(fullname, None) + if d is None: #if the full name is not there, create one + db = self.getDatabase() + d = EpicsDevice(fullname, parent=db, storeCallback=self._storeDev) #use full name + return d + + def getAttribute(self, attr_name): + """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. The + device associated to this attribute will also be created if necessary. + + :param attr_name: (str) the attribute name string. See + :mod:`taurus.core.epics` for valid attribute names + + :return: (EpicsAttribute) + + @throws TaurusException if the given name is invalid. + """ + a = self.epics_attrs.get(attr_name, None) #first try with the given name + if a is None: #if not, try with the full name + validator = EpicsAttribute.getNameValidator() + names = validator.getNames(attr_name) + if names is None: + raise TaurusException("Invalid epics attribute name %s" % attr_name) + fullname = names[0] + a = self.epics_attrs.get(fullname, None) + if a is None: #if the full name is not there, create one + dev = self.getDevice(validator.getDeviceName(attr_name)) + a = EpicsAttribute(fullname, parent=dev, storeCallback=self._storeAttr) #use full name + return a + + def getConfiguration(self, param): + """getConfiguration(param) -> taurus.core.taurusconfiguration.TaurusConfiguration + + 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[in] param taurus.core.taurusattribute.TaurusAttribute object or full configuration name + + @return a taurus.core.taurusattribute.TaurusAttribute object + @throws TaurusException if the given name is invalid. + """ + if isinstance(param, str): + return self._getConfigurationFromName(param) + return self._getConfigurationFromAttribute(param) + + def _getConfigurationFromName(self, cfg_name): + cfg = self.epics_configs.get(cfg_name, None) #first try with the given name + if cfg is None: #if not, try with the full name + validator = EpicsConfiguration.getNameValidator() + names = validator.getNames(cfg_name) + if names is None: + raise TaurusException("Invalid evaluation configuration name %s" % cfg_name) + fullname = names[0] + cfg = self.epics_configs.get(fullname, None) + if cfg is None: #if the full name is not there, create one + attr = self.getAttribute(validator.getAttrName(cfg_name)) + cfg = EpicsConfiguration(fullname, parent=attr, storeCallback=self._storeConfig) + return cfg + + def _getConfigurationFromAttribute(self, attr): + cfg = attr.getConfig() + cfg_name = attr.getFullName() + "?configuration" + self.epics_configs[cfg_name] = cfg + return cfg + + def _storeDev(self, dev): + name = dev.getFullName() + exists = self.epics_devs.get(name) + if exists is not None: + if exists == dev: + self.debug("%s has already been registered before" % name) + raise DoubleRegistration + else: + self.debug("%s has already been registered before with a different object!" % name) + raise DoubleRegistration + self.epics_devs[name] = dev + + def _storeAttr(self, attr): + name = attr.getFullName() + exists = self.epics_attrs.get(name) + if exists is not None: + if exists == attr: + self.debug("%s has already been registered before" % name) + raise DoubleRegistration + else: + self.debug("%s has already been registered before with a different object!" % name) + raise DoubleRegistration + self.epics_attrs[name] = attr + + def _storeConfig(self, fullname, config): + #name = config.getFullName() + name = fullname + exists = self.epics_configs.get(name) + if exists is not None: + if exists == config: + self.debug("%s has already been registered before" % name) + raise DoubleRegistration + else: + self.debug("%s has already been registered before with a different object!" % name) + raise DoubleRegistration + self.epics_configs[name] = config + + 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] + + + + +#=============================================================================== +# Just for testing +#=============================================================================== +def test1(): + f = EpicsFactory() + d = f.getDevice('epics://foo:bar:') + a = f.getAttribute('epics://foo:bar:baz') + p = a.getParentObj() + c = f.getConfiguration('epics://foo:bar:baz?configuration=label') +# cp = a.getConfig() + print "FACTORY:", f + print "DEVICE:", d, d.getSimpleName(), d.getNormalName(), d.getFullName() + print "ATTRIBUTE", a, a.getSimpleName(), a.getNormalName(), a.getFullName() + print "ATTRIBUTE PARENT", p, p.getSimpleName(), p.getNormalName(), p.getFullName(), p is d + print "CONFIGURATION", c, c.getSimpleName(), c.getNormalName(), c.getFullName() +# print "CONFIGPROXY", cp, cp.getSimpleName() +# print +# print c.getValueObj() +# print c.getUnit() + + +def test2(): + from taurus import Attribute + a = Attribute('epics://mp49t:sim1.RBV') + class Dummy: + n=0 + def eventReceived(self, s,t,v): + print "DUMMY:",self.n, v.value + self.n += 1 + kk = Dummy() + a.addListener(kk) + while kk.n <= 2: + time.sleep(1) + a.removeListener(kk) + while kk.n <= 20: + time.sleep(1) + +def test3(): + import sys + from taurus.qt.qtgui.application import TaurusApplication + from taurus.qt.qtgui.panel import TaurusForm + from taurus.qt.qtgui.plot import TaurusTrend +# from taurus.qt.qtgui.display import TaurusLabel + app = TaurusApplication() + + w = TaurusForm() + w.modifiableByUser=True + w2=TaurusTrend() +# w=TaurusLabel() + + w.setModel(['epics://mp49t:sim1.RBV', 'epics://mp49t:sim1.VAL', 'epics://mp49t:sim1.HIGH']) + w2.setModel(['epics://mp49t:sim1.RBV', 'epics://mp49t:sim1.VAL']) + +# a=w.getModelObj() +# print a, a.read().value + +# a=w.getModelObj() +# a.setUnit('asd') +# c=a.getConfig() + + w.show() + w2.show() + sys.exit(app.exec_()) + +if __name__ == "__main__": + test3() + + diff -Nru taurus-3.0.0/lib/taurus/core/evaluation/__init__.py taurus-3.1.0/lib/taurus/core/evaluation/__init__.py --- taurus-3.0.0/lib/taurus/core/evaluation/__init__.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/evaluation/__init__.py 2013-07-25 07:53:42.000000000 +0000 @@ -113,7 +113,7 @@ `eval://2*{tango://a/b/c/d}` - An attribute that adds two tango attributes together (note we can omit the `tango://` part - because tango is the default schema in taurus) + because tango is the default scheme in taurus) `eval://{a/b/c/d}+{f/g/h/i}` diff -Nru taurus-3.0.0/lib/taurus/core/evaluation/dev_example.py taurus-3.1.0/lib/taurus/core/evaluation/dev_example.py --- taurus-3.0.0/lib/taurus/core/evaluation/dev_example.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/evaluation/dev_example.py 2013-07-25 07:53:42.000000000 +0000 @@ -57,7 +57,7 @@ #=============================================================================== def test1(): - import taurus.core + import taurus a = taurus.Attribute('eval://dev=taurus.core.evaluation.dev_example.FreeSpaceDevice;getFreeSpace("/")/1024/1024') #calculates free space in Mb print "Free space: %iMb"%a.read().value diff -Nru taurus-3.0.0/lib/taurus/core/evaluation/evalfactory.py taurus-3.1.0/lib/taurus/core/evaluation/evalfactory.py --- taurus-3.0.0/lib/taurus/core/evaluation/evalfactory.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/evaluation/evalfactory.py 2013-07-25 07:53:42.000000000 +0000 @@ -32,15 +32,26 @@ -import os, time, re, weakref +import time, re, weakref import numpy +import taurus from taurus.core.taurusexception import TaurusException -import taurus.core -from taurus.core import OperationMode, MatchLevel, TaurusSWDevState, SubscriptionState, TaurusEventType -from taurus.core.util import SafeEvaluator +from taurus.core.tauruspollingtimer import TaurusPollingTimer +from taurus.core.taurusbasetypes import MatchLevel, TaurusSWDevState, \ + SubscriptionState, TaurusEventType, TaurusAttrValue, TaurusTimeVal, \ + AttrQuality +from taurus.core.util.log import Logger +from taurus.core.util.singleton import Singleton +from taurus.core.util.safeeval import SafeEvaluator +from taurus.core.taurusfactory import TaurusFactory +from taurus.core.taurusattribute import TaurusAttribute +from taurus.core.taurusdevice import TaurusDevice +from taurus.core.taurusdatabase import TaurusDatabase +from taurus.core.taurusconfiguration import TaurusConfiguration -class AbstractEvaluationNameValidator(taurus.core.util.Singleton): + +class AbstractEvaluationNameValidator(Singleton): #the object name class. *must* be implemented in subclasses name_pattern = '' #must be implemented in children classes # The following regexp pattern matches = pairs @@ -55,37 +66,37 @@ self.name_re = re.compile(self.name_pattern) self.kvsymbols_re = re.compile(self.kvsymbols_pattern) - def isValid(self,str, matchLevel = MatchLevel.ANY): - return self.name_re.match(str) is not None + def isValid(self,s, matchLevel = MatchLevel.ANY): + return self.name_re.match(s) is not None - def getParams(self, str): - m = self.attrname_re.match(str) + def getParams(self, s): + m = self.attrname_re.match(s) if m is None: return None return m.groupdict() - def getNames(self, str, factory=None): + def getNames(self, s, factory=None): """Returns the full, normal and simple names for this object, or None if there is no match''' """ - raise RunTimeError('Not Allowed to call this method from subclasses') + raise RuntimeError('Not Allowed to call this method from subclasses') - def getDeviceName(self, str, full=True): + def getDeviceName(self, s, full=True): ''' returns the device name for the given attribute name. If full=True, the returned name includes the DB name ''' - m = self.name_re.match(str) + m = self.name_re.match(s) if m is None: return None devname = m.group('devname') or EvaluationFactory.DEFAULT_DEVICE if full: - return '%s;dev=%s'%(self.getDBName(str),devname) + return '%s;dev=%s'%(self.getDBName(s),devname) else: return 'eval://dev=%s'%devname - def getDBName(self,str): + def getDBName(self,s): '''returns the full data base name for the given attribute name''' - m = self.name_re.match(str) + m = self.name_re.match(s) if m is None: return None dbname = m.group('dbname') or EvaluationFactory.DEFAULT_DATABASE @@ -93,7 +104,7 @@ class EvaluationAttributeNameValidator(AbstractEvaluationNameValidator): - # The groups in a match object using the regexp below are: + # The groups in a match object using the regexp below are: # 1: scheme; named as 'scheme' # 2: # 3: database name; optional; named as 'dbname' @@ -113,8 +124,8 @@ # 1 2 3 4 5 6 7 8 9 A name_pattern = r'^(?Peval|evaluation)://(db=(?P[^?#;]+);)?(dev=(?P[^?#;]+);)?(?P[^?#;]+)(\?(?!configuration=)(?P[^#?]*))?(#(?P.*))?$' - def isValid(self,str, matchLevel = MatchLevel.ANY): - m = self.name_re.match(str) + def isValid(self,s, matchLevel = MatchLevel.ANY): + m = self.name_re.match(s) if m is None: return False elif matchLevel == MatchLevel.COMPLETE: @@ -122,7 +133,7 @@ else: return True - def getNames(self, str, factory=None): + def getNames(self, s, factory=None): """Returns the complete, normal and short names. For example:: @@ -131,19 +142,19 @@ >>> ("eval://db=_DefaultEvalDB;dev=foo;123*{a/b/c/d}", "eval://dev=foo;bar*blah", "bar*blah") """ - m = self.name_re.match(str) + m = self.name_re.match(s) if m is None: return None #The following comments are for an example name like: "eval://dev=foo;bar*blah?bar=123;blah={a/b/c/d}#[1:-3]" attr_name = m.group('attrname') # attr_name = "bar*blah" - normal_name = "%s;%s"%(self.getDeviceName(str, full=False),attr_name) #normal_name = "eval://dev=foo;bar*blah" - expanded_attr_name = self.getExpandedTransformation(str) - fullname = "%s;%s"%(self.getDeviceName(str, full=True),expanded_attr_name) #fullname = "eval://db=_DefaultEvalDB;dev=foo;123*{a/b/c/d}" + normal_name = "%s;%s"%(self.getDeviceName(s, full=False),attr_name) #normal_name = "eval://dev=foo;bar*blah" + expanded_attr_name = self.getExpandedTransformation(s) + fullname = "%s;%s"%(self.getDeviceName(s, full=True),expanded_attr_name) #fullname = "eval://db=_DefaultEvalDB;dev=foo;123*{a/b/c/d}" return fullname, normal_name, attr_name - def getExpandedTransformation(self, str): + def getExpandedTransformation(self, s): 'expands the attribute name by substituting all symbols' - m = self.name_re.match(str) + m = self.name_re.match(s) if m is None: return None transf = m.group('attrname') @@ -167,23 +178,22 @@ # 1 2 3 4 5 6 7 name_pattern = r'^(?Peval|evaluation)://(db=(?P[^?#;]+);)?(dev=(?P[^?#;]+))(\?(?!configuration=)(?P[^#?]*))?$' - def getNames(self, str, factory=None): + def getNames(self, s, factory=None): """Returns the complete, normal and short names. (note: complete=normal) - :param str: (str) input string describing the device + :param s: (str) input string describing the device :param factory: (TaurusFactory) [Unused] :return: (tuple or None) A tuple of complete, normal and - short names, or None if str is an invalid device name + short names, or None if s is an invalid device name """ - m = self.name_re.match(str) + m = self.name_re.match(s) if m is None: return None - gdict = m.groupdict() #The following comments are for a name of the type: eval://dev=foo?bar=123;blah={a/b/c/d} devname = m.group('devname') # foo - normal_name = self.getDeviceName(str, full=False) #eval://dev=foo - full_name = self.getDeviceName(str, full=True) #eval://db=_DefaultEvalDB;dev=foo + normal_name = self.getDeviceName(s, full=False) #eval://dev=foo + full_name = self.getDeviceName(s, full=True) #eval://db=_DefaultEvalDB;dev=foo return full_name, normal_name, devname @@ -205,8 +215,8 @@ # 1 2 3 4 5 6 7 8 9 A name_pattern = r'^(?Peval|evaluation)://(db=(?P[^?#;]+);)?(dev=(?P[^?#;]+);)?(?P[^?#;]+)(\?(?!configuration=)(?P[^#?]*))?(\?configuration=?(?P[^#?]*))$' - def isValid(self,str, matchLevel = MatchLevel.ANY): - m = self.name_re.match(str) + def isValid(self,s, matchLevel = MatchLevel.ANY): + m = self.name_re.match(s) if m is None: return False elif matchLevel == MatchLevel.COMPLETE: @@ -214,27 +224,27 @@ else: return True - def getNames(self, str, factory=None): + def getNames(self, s, factory=None): """Returns the complete, normal and short names""" - m = self.name_re.match(str) + m = self.name_re.match(s) if m is None: return None #The following comments are for an example name like: "eval://dev=foo;bar*blah?bar=123;blah={a/b/c/d}?configuration=label" cfg_key = m.group('cfgkey') # cfg_key = "label" attr_name = m.group('attrname') - normal_name = "%s;%s?configuration"%(self.getDeviceName(str, full=False),attr_name) #normal_name = "eval://dev=foo;bar*blah?configuration" - expanded_attr_name = self.getExpandedTransformation(str) - fullname = "%s;%s?configuration"%(self.getDeviceName(str, full=True),expanded_attr_name) #fullname = "eval://db=_DefaultEvalDB;dev=foo;123*{a/b/c/d}?configuration" + normal_name = "%s;%s?configuration"%(self.getDeviceName(s, full=False),attr_name) #normal_name = "eval://dev=foo;bar*blah?configuration" + expanded_attr_name = self.getExpandedTransformation(s) + fullname = "%s;%s?configuration"%(self.getDeviceName(s, full=True),expanded_attr_name) #fullname = "eval://db=_DefaultEvalDB;dev=foo;123*{a/b/c/d}?configuration" return fullname, normal_name, cfg_key - def getAttrName(self, str): - names = self.getNames(str) + def getAttrName(self, s): + names = self.getNames(s) if names is None: return None return names[0][:-len('?configuration')] #remove the "?configuration" substring from the fullname - def getExpandedTransformation(self, str): + def getExpandedTransformation(self, s): 'expands the attribute name by substituting all symbols' - m = self.name_re.match(str) + m = self.name_re.match(s) if m is None: return None transf = m.group('attrname') @@ -243,7 +253,7 @@ transf = re.sub(k,v, transf) return transf -class EvaluationDatabase(taurus.core.TaurusDatabase): +class EvaluationDatabase(TaurusDatabase): ''' Dummy database class for Evaluation (the Database concept is not used in the Evaluation scheme) @@ -257,7 +267,7 @@ return "EvaluationDatabase object calling %s" % name -class EvaluationDevice(taurus.core.TaurusDevice, SafeEvaluator): +class EvaluationDevice(TaurusDevice, SafeEvaluator): ''' The evaluator object. It is a :class:`TaurusDevice` and is used as the parent of :class:`EvaluationAttribute` objects for which it performs the @@ -272,7 +282,7 @@ def __init__(self, name, **kw): """Object initialization.""" - self.call__init__(taurus.core.TaurusDevice, name, **kw) + self.call__init__(TaurusDevice, name, **kw) safedict = {} for s in self._symbols: if hasattr(self,s): @@ -313,12 +323,12 @@ else: self.info("Unexpected value to decode: %s" % str(event_value)) new_sw_state = TaurusSWDevState.Crash - value = taurus.core.TaurusAttrValue() + value = TaurusAttrValue() value.value = new_sw_state return value -class EvaluationAttribute(taurus.core.TaurusAttribute): +class EvaluationAttribute(TaurusAttribute): ''' A :class:`TaurusAttribute` that can be used to perform mathematical operations involving other arbitrary Taurus attributes. The mathematical @@ -336,15 +346,15 @@ cref_RegExp = re.compile("\{(.+?)\}") #regexp for references to other taurus models within operation model names def __init__(self, name, parent, storeCallback = None): - self.call__init__(taurus.core.TaurusAttribute, name, parent, storeCallback=storeCallback) + self.call__init__(TaurusAttribute, name, parent, storeCallback=storeCallback) - self._value = taurus.core.TaurusAttrValue() + self._value = TaurusAttrValue() self._value.config.writable = False #Evaluation Attributes are always read-only (at least for now) self._references = [] self._validator= self.getNameValidator() self._transformation = None # reference to the configuration object - self.__attr_config = None#taurus.core.TaurusConfiguration() + self.__attr_config = None#taurus.core.configuration.TaurusConfiguration() self.__subscription_state = SubscriptionState.Unsubscribed @@ -476,11 +486,11 @@ try: evaluator = self.getParentObj() self._value.value = evaluator.eval(self._transformation) - self._value.time = taurus.core.TaurusTimeVal.now() - self._value.quality = taurus.core.AttrQuality.ATTR_VALID + self._value.time = TaurusTimeVal.now() + self._value.quality = AttrQuality.ATTR_VALID self._value.config.data_format = len(numpy.shape(self._value.value)) except Exception, e: - self._value.quality = taurus.core.AttrQuality.ATTR_INVALID + self._value.quality = AttrQuality.ATTR_INVALID self.warning("the function '%s' could not be evaluated. Reason: %s"%(self._transformation, repr(e))) #self.traceback(taurus.Warning) @@ -567,7 +577,7 @@ initial_subscription_state = self.__subscription_state - ret = taurus.core.TaurusAttribute.addListener(self, listener) + ret = TaurusAttribute.addListener(self, listener) if not ret: return ret @@ -587,7 +597,7 @@ """ Remove a TaurusListener from the listeners list. If polling enabled and it is the last element then stop the polling timer. If the listener is not registered nothing happens.""" - ret = taurus.core.TaurusAttribute.removeListener(self, listener) + ret = TaurusAttribute.removeListener(self, listener) cfg = self._getRealConfig() cfg.removeListener(listener) @@ -598,7 +608,7 @@ return ret -class EvaluationConfiguration(taurus.core.TaurusConfiguration): +class EvaluationConfiguration(TaurusConfiguration): ''' A :class:`TaurusConfiguration` @@ -608,7 +618,7 @@ Instead it should be done via the :meth:`EvaluationFactory.getConfig` ''' def __init__(self, name, parent, storeCallback = None): - self.call__init__(taurus.core.TaurusConfiguration, name, parent, storeCallback=storeCallback) + self.call__init__(TaurusConfiguration, name, parent, storeCallback=storeCallback) #fill the attr info i = parent.read().config @@ -644,7 +654,7 @@ """ Returns the current configuration for the attribute.""" return self._attr_info -class EvaluationFactory(taurus.core.util.Singleton, taurus.core.TaurusFactory, taurus.core.util.Logger): +class EvaluationFactory(Singleton, TaurusFactory, Logger): """ A Singleton class that provides Evaluation related objects. """ @@ -659,8 +669,8 @@ def init(self, *args, **kwargs): """Singleton instance initialization.""" name = self.__class__.__name__ - self.call__init__(taurus.core.util.Logger, name) - self.call__init__(taurus.core.TaurusFactory) + self.call__init__(Logger, name) + self.call__init__(TaurusFactory) self.eval_attrs = weakref.WeakValueDictionary() self.eval_devs = weakref.WeakValueDictionary() self.eval_configs = weakref.WeakValueDictionary() @@ -753,15 +763,15 @@ return a def getConfiguration(self, param): - """getConfiguration(param) -> taurus.core.TaurusConfiguration + """getConfiguration(param) -> taurus.core.taurusconfiguration.TaurusConfiguration 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[in] param taurus.core.TaurusAttribute object or full configuration name + @param[in] param taurus.core.taurusattribute.TaurusAttribute object or full configuration name - @return a taurus.core.TaurusAttribute object + @return a taurus.core.taurusattribute.TaurusAttribute object @throws TaurusException if the given name is invalid. """ if isinstance(param, str): @@ -784,7 +794,7 @@ def _getConfigurationFromAttribute(self, attr): cfg = attr.getConfig() - cfg_name = attrObj.getFullName() + "?configuration" + cfg_name = attr.getFullName() + "?configuration" self.eval_configs[cfg_name] = cfg return cfg @@ -794,10 +804,10 @@ if exists is not None: if exists == dev: self.debug("%s has already been registered before" % name) - raise taurus.core.DoubleRegistration + raise DoubleRegistration else: self.debug("%s has already been registered before with a different object!" % name) - raise taurus.core.DoubleRegistration + raise DoubleRegistration self.eval_devs[name] = dev def _storeAttr(self, attr): @@ -806,10 +816,10 @@ if exists is not None: if exists == attr: self.debug("%s has already been registered before" % name) - raise taurus.core.DoubleRegistration + raise DoubleRegistration else: self.debug("%s has already been registered before with a different object!" % name) - raise taurus.core.DoubleRegistration + raise DoubleRegistration self.eval_attrs[name] = attr def _storeConfig(self, fullname, config): @@ -819,10 +829,10 @@ if exists is not None: if exists == config: self.debug("%s has already been registered before" % name) - raise taurus.core.DoubleRegistration + raise DoubleRegistration else: self.debug("%s has already been registered before with a different object!" % name) - raise taurus.core.DoubleRegistration + raise DoubleRegistration self.eval_configs[name] = config def addAttributeToPolling(self, attribute, period, unsubscribe_evts = False): @@ -833,7 +843,7 @@ :param period: (float) polling period (in seconds) :param unsubscribe_evts: (bool) whether or not to unsubscribe from events """ - tmr = self.polling_timers.get(period,taurus.core.TaurusPollingTimer(period)) + tmr = self.polling_timers.get(period, TaurusPollingTimer(period)) self.polling_timers[period] = tmr tmr.addAttribute(attribute, self.isPollingEnabled()) @@ -876,7 +886,6 @@ def test2(): - import taurus.core a=taurus.Attribute('eval://[{sys/tg_test/1/short_scalar},{sys/tg_test/1/double_scalar}, {sys/tg_test/1/short_scalar}+{sys/tg_test/1/double_scalar}]') #a=taurus.Attribute('eval://2*{sys/tg_test/1/short_scalar}+rand()') class Dummy: @@ -896,8 +905,8 @@ import sys from taurus.qt.qtgui.application import TaurusApplication from taurus.qt.qtgui.panel import TaurusForm - from taurus.qt.qtgui.plot import TaurusTrend - from taurus.qt.qtgui.display import TaurusLabel + #from taurus.qt.qtgui.plot import TaurusTrend + #from taurus.qt.qtgui.display import TaurusLabel app = TaurusApplication() w = TaurusForm() diff -Nru taurus-3.0.0/lib/taurus/core/evaluation/ipap_example.py taurus-3.1.0/lib/taurus/core/evaluation/ipap_example.py --- taurus-3.0.0/lib/taurus/core/evaluation/ipap_example.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/evaluation/ipap_example.py 2013-07-25 07:53:42.000000000 +0000 @@ -64,7 +64,7 @@ try: value = self.ipap.readParameter(axis, param) - return double(value) + return float(value) except: return value diff -Nru taurus-3.0.0/lib/taurus/core/init_bkcomp.py taurus-3.1.0/lib/taurus/core/init_bkcomp.py --- taurus-3.0.0/lib/taurus/core/init_bkcomp.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/init_bkcomp.py 2013-07-25 07:53:43.000000000 +0000 @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""The core module""" + +__docformat__ = "restructuredtext" + +import release as Release +#from .enums import * #note: all the enums from enums.py were moved to taurusbasetypes.py +from .taurusbasetypes import * +from .taurusexception import * +from .taurusmodel import * +from .tauruslistener import * +from .taurusdevice import * +from .taurusattribute import * +from .taurusconfiguration import * +from .taurusdatabase import * +from .taurusfactory import * +from .taurusmanager import * +from .taurusoperation import * +from .tauruspollingtimer import * +from .taurusvalidator import * + +# enable compatibility code with tau V1 if tauv1 package is present +try: + from .tauv1 import * +except: + pass + diff -Nru taurus-3.0.0/lib/taurus/core/init_lightweight.py taurus-3.1.0/lib/taurus/core/init_lightweight.py --- taurus-3.0.0/lib/taurus/core/init_lightweight.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/init_lightweight.py 2013-07-25 07:53:43.000000000 +0000 @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""The core module""" + +__docformat__ = "restructuredtext" + +#import release as Release +from .taurusbasetypes import * +# from .taurusexception import * +# from .taurusmodel import * +# from .tauruslistener import * +# from .taurusdevice import * +# from .taurusattribute import * +# from .taurusconfiguration import * +# from .taurusdatabase import * +# from .taurusfactory import * +# from .taurusmanager import * +# from .taurusoperation import * +# from .tauruspollingtimer import * +# from .taurusvalidator import * diff -Nru taurus-3.0.0/lib/taurus/core/release.py taurus-3.1.0/lib/taurus/core/release.py --- taurus-3.0.0/lib/taurus/core/release.py 2012-04-30 07:51:52.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/release.py 2013-07-25 07:53:43.000000000 +0000 @@ -53,7 +53,7 @@ # bdist_deb does not accept underscores (a Debian convention). -version_info = (3,0,0,'final',0) +version_info = (3,1,0,'rc',0) version = '.'.join(map(str, version_info[:3])) revision = str(version_info[4]) @@ -65,7 +65,7 @@ license = 'LGPL' -authors = {'Tiago' : ('Tiago Coutinho','tcoutinho@cells.es'), +authors = {'Tiago' : ('Tiago Coutinho','tiago.coutinho@esrf.fr'), 'Pascual-Izarra' : ('Carlos Pascual-Izarra','cpascual@cells.es') } diff -Nru taurus-3.0.0/lib/taurus/core/resource/resfactory.py taurus-3.1.0/lib/taurus/core/resource/resfactory.py --- taurus-3.0.0/lib/taurus/core/resource/resfactory.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/resource/resfactory.py 2013-07-25 07:53:42.000000000 +0000 @@ -29,9 +29,17 @@ import os, imp, operator, types -import taurus.core -import taurus.core.util -from taurus.core import OperationMode, MatchLevel +from taurus import Factory, Database, Manager +from taurus.core.taurusexception import TaurusException +from taurus.core.taurusbasetypes import OperationMode, MatchLevel, \ + TaurusAttrValue, TaurusEventType +from taurus.core.util.singleton import Singleton +from taurus.core.util.log import Logger +from taurus.core.taurusfactory import TaurusFactory +from taurus.core.taurusattribute import TaurusAttribute +from taurus.core.taurusdevice import TaurusDevice +from taurus.core.taurusdatabase import TaurusDatabase +from taurus.core.taurusconfiguration import TaurusConfiguration class ModuleDict(dict): def __init__(self, mod): @@ -40,7 +48,7 @@ def __getitem__(self, name): return self.__mod.__getattribute__(name) -class ResourcesFactory(taurus.core.util.Singleton, taurus.core.TaurusFactory, taurus.core.util.Logger): +class ResourcesFactory(Singleton, TaurusFactory, Logger): """A Singleton class designed to provide Simulation related objects.""" #: the list of schemes that this factory supports. For this factory: 'res' @@ -61,8 +69,8 @@ """Singleton instance initialization. **For internal usage only**""" name = self.__class__.__name__ - self.call__init__(taurus.core.util.Logger, name) - self.call__init__(taurus.core.TaurusFactory) + self.call__init__(Logger, name) + self.call__init__(TaurusFactory) self._resource_map = {} self._resource_priority = {} @@ -159,7 +167,7 @@ return i, c, alias.split(c, 1) return None, '', [alias] - def __splitSchema(self, alias): + def __splitScheme(self, alias): try: i = alias.index('://') return alias[:i], alias[i+3:] @@ -173,7 +181,7 @@ :return: (str) the value for the given key """ - alias = self.__splitSchema(key) + alias = self.__splitScheme(key) if alias[0] and not alias[0] in ResourcesFactory.schemes: return None i, c, alias = self.__splitResourceName(alias[1]) @@ -186,8 +194,8 @@ :param absolute_name: (str) the object absolute name string - :return: (taurus.core.TaurusModel) a class object that should be a subclass of a taurus.core.TaurusModel - :raise: (taurus.core.TaurusException) if the given name is invalid. + :return: (taurus.core.taurusmodel.TaurusModel) a class object that should be a subclass of a taurus.core.taurusmodel.TaurusModel + :raise: (taurus.core.taurusexception.TaurusException) if the given name is invalid. """ objType = None @@ -203,18 +211,18 @@ :param alias: (str) database name string alias. If None, the default database is used - :return: (taurus.core.TaurusDatabase) database object + :return: (taurus.core.taurusdatabase.TaurusDatabase) database object :raise: (NameError) if the alias does not exist - :raise: (taurus.core.TaurusException) if the given alias is invalid. + :raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid. """ if alias is None: - return taurus.Database() + return Database() alias = self.getValue(alias) if not alias: raise NameError(alias) - return taurus.Manager().getDatabase(alias) + return Manager().getDatabase(alias) def getDevice(self, alias): """ @@ -224,14 +232,14 @@ :param alias: device name string alias. - :return: (taurus.core.TaurusDevice) device object + :return: (taurus.core.taurusdevice.TaurusDevice) device object :raise: (NameError) if the alias does not exist - :raise: (taurus.core.TaurusException) if the given alias is invalid. + :raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid. """ alias = self.getValue(alias) if not alias: raise NameError(alias) - return taurus.Manager().getDevice(alias) + return Manager().getDevice(alias) def getAttribute(self, alias): """ @@ -241,14 +249,14 @@ :param alias: (str) attribute name string alias - :return: (taurus.core.TaurusAttribute) attribute object + :return: (taurus.core.taurusattribute.TaurusAttribute) attribute object :raise: (NameError) if the alias does not exist - :raise: (taurus.core.TaurusException) if the given alias is invalid. + :raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid. """ alias = self.getValue(alias) if not alias: raise NameError(alias) - return taurus.Manager().getAttribute(alias) + return Manager().getAttribute(alias) def getConfiguration(self, alias): """ @@ -258,12 +266,12 @@ :param alias: (str) configuration name string alias - :return: (taurus.core.TaurusConfiguration) configuration object + :return: (taurus.core.taurusconfiguration.TaurusConfiguration) configuration object :raise: (NameError) if the alias does not exist - :raise: (taurus.core.TaurusException) if the given alias is invalid. + :raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid. """ alias = self.getValue(alias) if not alias: raise NameError(alias) - return taurus.Manager().getConfiguration(alias) + return Manager().getConfiguration(alias) diff -Nru taurus-3.0.0/lib/taurus/core/simulation/simfactory.py taurus-3.1.0/lib/taurus/core/simulation/simfactory.py --- taurus-3.0.0/lib/taurus/core/simulation/simfactory.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/simulation/simfactory.py 2013-07-25 07:53:42.000000000 +0000 @@ -36,14 +36,20 @@ authority """ -import os +from taurus import Factory +from taurus.core.taurusexception import TaurusException +from taurus.core.taurusbasetypes import OperationMode, MatchLevel, \ + TaurusAttrValue, TaurusEventType +from taurus.core.util.log import Logger +from taurus.core.util.singleton import Singleton +from taurus.core.taurusfactory import TaurusFactory +from taurus.core.taurusattribute import TaurusAttribute +from taurus.core.taurusdevice import TaurusDevice +from taurus.core.taurusdatabase import TaurusDatabase +from taurus.core.taurusconfiguration import TaurusConfiguration -import taurus.core -import taurus.core.util -from taurus.core import OperationMode, MatchLevel - -class SimulationDatabase(taurus.core.TaurusDatabase): +class SimulationDatabase(TaurusDatabase): def factory(self): return SimulationFactory() @@ -54,13 +60,13 @@ return "a/b/c" def cache(self): - return taurus.Factory('tango').getDatabase().cache() + return Factory('tango').getDatabase().cache() def __getattr__(self, name): return "SimulationDatabase object calling %s" % name -class SimulationDevice(taurus.core.TaurusDevice): +class SimulationDevice(TaurusDevice): def _createHWObject(self): return "Simulation" @@ -73,7 +79,7 @@ class D: pass -class SimulationConfiguration(taurus.core.TaurusConfiguration): +class SimulationConfiguration(TaurusConfiguration): def __init__(self, name, parent, storeCallback = None): i = D() @@ -116,7 +122,7 @@ i.attr_name = attr.getSimpleName() i.attr_fullname = attr.getNormalName() self.attr_info = i - self.call__init__(taurus.core.TaurusConfiguration, name, parent, storeCallback=storeCallback) + self.call__init__(TaurusConfiguration, name, parent, storeCallback=storeCallback) def factory(self): return SimulationFactory() @@ -159,16 +165,16 @@ return value -class SimulationAttribute(taurus.core.TaurusAttribute): +class SimulationAttribute(TaurusAttribute): def __init__(self, name, parent, storeCallback = None): - self._value = taurus.core.TaurusAttrValue() + self._value = TaurusAttrValue() self._config = None self._value.value = 123.45 self._value.w_value = 123.45 self._value.quality = "ATTR_VALID" self._value.time_stamp = 1 - self.call__init__(taurus.core.TaurusAttribute, name, parent, storeCallback=storeCallback) + self.call__init__(TaurusAttribute, name, parent, storeCallback=storeCallback) def __getattr__(self,name): return getattr(self.getConfig(), name) @@ -218,18 +224,18 @@ If it is the first element and Polling is enabled starts the polling mechanism. If the listener is already registered nothing happens.""" - ret = taurus.core.TaurusAttribute.addListener(self, listener) + ret = TaurusAttribute.addListener(self, listener) if not ret: return ret #fire a first configuration event cfg_val, val = self.getConfig().getValueObj(), self.read() - self.fireEvent(taurus.core.TaurusEventType.Config, cfg_val, listener) + self.fireEvent(TaurusEventType.Config, cfg_val, listener) #fire a first change event - self.fireEvent(taurus.core.TaurusEventType.Change, val, listener) + self.fireEvent(TaurusEventType.Change, val, listener) return ret -class SimulationFactory(taurus.core.util.Singleton, taurus.core.TaurusFactory, taurus.core.util.Logger): +class SimulationFactory(Singleton, TaurusFactory, Logger): """A Singleton class designed to provide Simulation related objects.""" schemes = ("simulation",) @@ -241,17 +247,17 @@ def init(self, *args, **kwargs): """Singleton instance initialization.""" name = self.__class__.__name__ - self.call__init__(taurus.core.util.Logger, name) - self.call__init__(taurus.core.TaurusFactory) + self.call__init__(Logger, name) + self.call__init__(TaurusFactory) def findObjectClass(self, absolute_name): - """findObjectClass(string absolute_name) -> taurus.core.TaurusModel subclass + """findObjectClass(string absolute_name) -> taurus.core.taurusmodel.TaurusModel subclass Obtain the class object corresponding to the given name. @param[in] absolute_name the object absolute name string - @return a class object that should be a subclass of a taurus.core.TaurusModel + @return a class object that should be a subclass of a taurus.core.taurusmodel.TaurusModel @throws TaurusException if the given name is invalid. """ objType = None @@ -270,7 +276,7 @@ return objType def getDatabase(self, db_name=None): - """getDatabase(string db_name) -> taurus.core.TaurusDatabase + """getDatabase(string db_name) -> taurus.core.taurusdatabase.TaurusDatabase Obtain the object corresponding to the given database name or the default database if db_name is None. @@ -278,43 +284,43 @@ instance is returned. Otherwise a new instance is stored and returned. @param[in] db_name database name string. It should be formed like: - ://. If is ommited then - it will use the default schema. if db_name is None, + ://. If is ommited then + it will use the default scheme. if db_name is None, the default database is used - @return a taurus.core.TaurusDatabase object + @return a taurus.core.taurusdatabase.TaurusDatabase object @throws TaurusException if the given name is invalid. """ if not db_name is None: validator = SimulationDatabase.getNameValidator() params = validator.getParams(db_name) if params is None: - raise taurus.core.TaurusException("Invalid database name %s." % db_name) + raise TaurusException("Invalid database name %s." % db_name) if not hasattr(self, "_db"): self._db = SimulationDatabase("sim:01") return self._db def getDevice(self, dev_name): - """getDevice(string dev_name) -> taurus.core.TaurusDevice + """getDevice(string dev_name) -> taurus.core.taurusdevice.TaurusDevice Obtain the object corresponding to the given device name. If the corresponding device already exists, the existing instance is returned. Otherwise a new instance is stored and returned. @param[in] dev_name the device name string. It should be formed like: - :///. If - is ommited then it will use the default schema. + :///. If + is ommited then it will use the default scheme. If authority is ommited then it will use the - default authority for the schema. + default authority for the scheme. - @return a taurus.core.TaurusDevice object + @return a taurus.core.taurusdevice.TaurusDevice object @throws TaurusException if the given name is invalid. """ validator = SimulationDevice.getNameValidator() params = validator.getParams(dev_name) if params is None: - raise taurus.core.TaurusException("Invalid device name %s." % dev_name) + raise TaurusException("Invalid device name %s." % dev_name) if not hasattr(self, "_dev"): db = self.getDatabase("sim:01") @@ -322,7 +328,7 @@ return self._dev def getAttribute(self, attr_name): - """getAttribute(string attr_name) -> taurus.core.TaurusAttribute + """getAttribute(string attr_name) -> taurus.core.taurusattribute.TaurusAttribute Obtain the object corresponding to the given attribute name. If the corresponding attribute already exists, the existing instance @@ -330,14 +336,14 @@ @param[in] attr_name string attribute name - @return a taurus.core.TaurusAttribute object + @return a taurus.core.taurusattribute.TaurusAttribute object @throws TaurusException if the given name is invalid. """ validator = SimulationAttribute.getNameValidator() params = validator.getParams(attr_name) if params is None: - raise taurus.core.TaurusException("Invalid attribute name %s." % attr_name) + raise TaurusException("Invalid attribute name %s." % attr_name) if not hasattr(self, "_attr"): dev = self.getDevice("sim:01/a/b/c") @@ -345,15 +351,15 @@ return self._attr def getConfiguration(self, param): - """getConfiguration(param) -> taurus.core.TaurusConfiguration + """getConfiguration(param) -> taurus.core.taurusconfiguration.TaurusConfiguration 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[in] param taurus.core.TaurusAttribute object or full configuration name + @param[in] param taurus.core.taurusattribute.TaurusAttribute object or full configuration name - @return a taurus.core.TaurusAttribute object + @return a taurus.core.taurusattribute.TaurusAttribute object @throws TaurusException if the given name is invalid. """ if isinstance(param, str): @@ -365,7 +371,7 @@ params = validator.getParams(name) if params is None: - raise taurus.core.TaurusException("Invalid configuration name %s." % name) + raise taurus.core.taurusexception.TaurusException("Invalid configuration name %s." % name) if not hasattr(self, "_conf"): name = "sim:01/a/b/c/d?configuration" diff -Nru taurus-3.0.0/lib/taurus/core/tango/__init__.py taurus-3.1.0/lib/taurus/core/tango/__init__.py --- taurus-3.0.0/lib/taurus/core/tango/__init__.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/__init__.py 2013-07-25 07:53:42.000000000 +0000 @@ -31,7 +31,7 @@ be omited. You should never create objects of tango classes directly. Instead you -should use the :class:`taurus.core.TaurusManager` and :class:`taurus.core.TaurusFactory` APIs +should use the :class:`taurus.core.taurusmanager.TaurusManager` and :class:`taurus.core.taurusfactory.TaurusFactory` APIs to access all elements. For example, to get a reference to the Tango attribute my/tango/device/state you diff -Nru taurus-3.0.0/lib/taurus/core/tango/enums.py taurus-3.1.0/lib/taurus/core/tango/enums.py --- taurus-3.0.0/lib/taurus/core/tango/enums.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/enums.py 2013-07-25 07:53:42.000000000 +0000 @@ -30,15 +30,14 @@ __docformat__ = "restructuredtext" -import taurus.core.util +from taurus.core.taurusbasetypes import SubscriptionState +from taurus.core.util.enumeration import Enumeration -TangoObjectType = taurus.core.util.Enumeration("TangoObjectType", +TangoObjectType = Enumeration("TangoObjectType", ["Database", "Server", "Class", "Device", "Attribute","Property","Configuration", "Object"]) -SubscriptionState = taurus.core.SubscriptionState #moved from here to taurus.core. Copied here for backwards compatibility - import numpy import PyTango diff -Nru taurus-3.0.0/lib/taurus/core/tango/img/img.py taurus-3.1.0/lib/taurus/core/tango/img/img.py --- taurus-3.0.0/lib/taurus/core/tango/img/img.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/img/img.py 2013-07-25 07:53:42.000000000 +0000 @@ -31,15 +31,16 @@ __docformat__ = 'restructuredtext' -import taurus.core -import taurus.core.tango -import taurus.core.util -class ImageDevice(taurus.core.tango.TangoDevice): +from taurus.core.taurusbasetypes import TaurusEventType +from taurus.core.tango import TangoDevice +from taurus.core.util.containers import CaselessDict + +class ImageDevice(TangoDevice): """A class encapsulating a generic image device""" def __init__(self, name, image_name='image', **kw): - self.call__init__(taurus.core.tango.TangoDevice, name, **kw) + self.call__init__(TangoDevice, name, **kw) self.setImageAttrName(image_name) def addImageAttrName(self, attr_name): @@ -48,7 +49,7 @@ self._image_attr_names.append(attr_name) def setImageAttrName(self, attr_name): - self._image_attr_names = taurus.core.util.CaselessList() + self._image_attr_names = CaselessList() self.addImageAttrName(attr_name) def getImageAttrName(self, idx=0): @@ -56,13 +57,14 @@ def getImageAttrNames(self): return self._image_attr_names - + + class ImageCounterDevice(ImageDevice): """A class encapsulating a generic image device that has an image counter attribute""" def __init__(self, name, image_name='image', **kw): - self._image_data = taurus.core.util.CaselessDict() + self._image_data = CaselessDict() self.call__init__(ImageDevice, name, **kw) self._image_id_attr = self.getAttribute(self.getImageIDAttrName()) self._image_id_attr.addListener(self) @@ -87,7 +89,7 @@ def eventReceived(self, evt_src, evt_type, evt_value): if evt_src == self._image_id_attr: - if evt_type == taurus.core.TaurusEventType.Change: + if evt_type == TaurusEventType.Change: self._setDirty() self.fireEvent(evt_type, evt_value) else: @@ -123,7 +125,7 @@ def eventReceived(self, evt_src, evt_type, evt_value): if evt_src == self.getAttribute("imageformat"): - if evt_type in (taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic): + if evt_type in (TaurusEventType.Change, TaurusEventType.Periodic): self._color = evt_value.value.lower() == "rgb24" return ImageCounterDevice.eventReceived(self, evt_src, evt_type, evt_value) diff -Nru taurus-3.0.0/lib/taurus/core/tango/sardana/macro.py taurus-3.1.0/lib/taurus/core/tango/sardana/macro.py --- taurus-3.0.0/lib/taurus/core/tango/sardana/macro.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/sardana/macro.py 2013-07-25 07:53:42.000000000 +0000 @@ -38,7 +38,10 @@ import threading import PyTango -from taurus.core.util import etree, USER_NAME, CodecFactory +from lxml import etree + +from taurus.core.util.user import USER_NAME +from taurus.core.util.codecs import CodecFactory class MacroRunException(Exception): pass diff -Nru taurus-3.0.0/lib/taurus/core/tango/sardana/macroserver.py taurus-3.1.0/lib/taurus/core/tango/sardana/macroserver.py --- taurus-3.0.0/lib/taurus/core/tango/sardana/macroserver.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/sardana/macroserver.py 2013-07-25 07:53:42.000000000 +0000 @@ -3,21 +3,21 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## @@ -25,16 +25,13 @@ """The macroserver submodule. It contains specific part of macroserver""" -__all__ = [ 'BaseDoor', 'BaseMacroServer', 'registerExtensions' ] +__all__ = [ 'BaseInputHandler', 'BaseDoor', 'BaseMacroServer', + 'registerExtensions' ] __docformat__ = 'restructuredtext' import sys -import re import weakref -import copy -import types -import operator import threading import time import uuid @@ -42,17 +39,25 @@ import PyTango +from lxml import etree + from taurus import Device, Factory -from taurus.core import TaurusEventType, TaurusSWDevState, \ +from taurus.core.taurusmanager import TaurusManager +from taurus.core.taurusbasetypes import TaurusEventType, TaurusSWDevState, \ TaurusSerializationMode -from taurus.core.util import etree, CodecFactory, CaselessDict, Logger, \ - EventGenerator, AttributeEventWait -from taurus.core.util.console import NoColors, TermColors + +from taurus.core.util.log import Logger +from taurus.core.util.singleton import Singleton +from taurus.core.util.containers import CaselessDict +from taurus.core.util.codecs import CodecFactory +from taurus.core.util.event import EventGenerator, AttributeEventWait from taurus.core.tango import TangoDevice -from macro import MacroInfo, Macro, MacroNode, ParamFactory, RepeatNode, RepeatParamNode, SingleParamNode, ParamNode -from sardana import BaseSardanaElementContainer, BaseSardanaElement -from pool import getChannelConfigs +from .macro import MacroInfo, Macro, MacroNode, ParamFactory, RepeatNode, \ + RepeatParamNode, SingleParamNode, ParamNode +from .sardana import BaseSardanaElementContainer, BaseSardanaElement +from .pool import getChannelConfigs + CHANGE_EVT_TYPES = TaurusEventType.Change, TaurusEventType.Periodic @@ -65,9 +70,9 @@ self.call__init__(Logger, name) event_name = '%s %s' % (dev.getNormalName(), name) self.call__init__(EventGenerator, event_name) - + self._attr.addListener(self) - + def eventReceived(self, src, type, evt_value): if type == TaurusEventType.Error: self.fireEvent(None) @@ -76,7 +81,7 @@ self.fireEvent(evt_value.value) else: self.fireEvent(None) - + def getTaurusAttribute(self): return self._attr @@ -85,18 +90,18 @@ class LogAttr(Attr): - + def __init__(self, dev, name, obj_class, attr, max_buff_size=4096): self._log_buffer = [] self._max_buff_size = max_buff_size self.call__init__(Attr, dev, name, obj_class, attr) - + def getLogBuffer(self): return self._log_buffer - + def clearLogBuffer(self): self._log_buffer = [] - + def eventReceived(self, src, type, evt_value): if type == TaurusEventType.Change: if evt_value is None or evt_value.value is None: @@ -109,10 +114,36 @@ self.fireEvent(evt_value.value) +class BaseInputHandler(object): + + def __init__(self): + try: + self._input = raw_input + except NameError: + self._input = input + + def input(self, input_data=None): + if input_data is None: + input_data = {} + prompt = input_data.get('prompt') + ret = dict(input=None, cancel=False) + try: + if prompt is None: + ret['input'] = self._input() + else: + ret['input'] = self._input(prompt) + except: + ret['cancel'] = True + return ret + + def input_timeout(self, input_data): + print "input timeout" + + class MacroServerDevice(TangoDevice): - """A class encapsulating a generic macro server device (usually a + """A class encapsulating a generic macro server device (usually a MacroServer or a Door""" - + def _getEventWait(self): if not hasattr(self, '_evt_wait'): # create an object that waits for attribute events. @@ -122,17 +153,17 @@ class ExperimentConfiguration(object): - + def __init__(self, door): self._door = door - + def get(self, cache=False): door = self._door macro_server = door.macro_server env = door.getEnvironment() - + ret = dict(ScanDir=env.get('ScanDir'), - DataCompressionRank=env.get('DataCompressionRank', -1), + DataCompressionRank=env.get('DataCompressionRank', 0), PreScanSnapshot=env.get('PreScanSnapshot', [])) scan_file = env.get('ScanFile') if scan_file is None: @@ -141,21 +172,21 @@ scan_file = [scan_file] ret['ScanFile'] = scan_file mnt_grps = macro_server.getElementNamesOfType("MeasurementGroup") - + active_mnt_grp = env.get('ActiveMntGrp') if active_mnt_grp is None and len(mnt_grps): active_mnt_grp = mnt_grps[0] door.putEnvironment('ActiveMntGrp', active_mnt_grp) - + ret['ActiveMntGrp'] = active_mnt_grp ret['MntGrpConfigs'] = mnt_grp_configs = CaselessDict() - + if len(mnt_grps) == 0: return ret - + mnt_grp_grps = PyTango.Group("grp") mnt_grp_grps.add(mnt_grps) - + codec = CodecFactory().getCodec('json') replies = mnt_grp_grps.read_attribute("configuration") for mnt_grp, reply in zip(mnt_grps, replies): @@ -163,7 +194,7 @@ codec.decode(('json', reply.get_data().value), ensure_ascii=True)[1] return ret - + def set(self, conf, mnt_grps=None): """Sets the ExperimentConfiguration dictionary.""" env = dict(ScanDir=conf.get('ScanDir'), @@ -174,37 +205,49 @@ if mnt_grps is None: mnt_grps = conf['MntGrpConfigs'].keys() self._door.putEnvironments(env) - + codec = CodecFactory().getCodec('json') for mnt_grp in mnt_grps: - mnt_grp_cfg = conf['MntGrpConfigs'][mnt_grp] - if mnt_grp_cfg is None: #a deleted mntGrp - self._pool.DeleteElement(mnt_grp) - else: - try: - mnt_grp_dev = Device(mnt_grp) - except: #if the mnt_grp did not already exist, create it now - chconfigs = getChannelConfigs(mnt_grp_cfg) - chnames,chinfos = zip(*chconfigs) #unzipping - self._pool.createMeasurementGroup([mnt_grp]+list(chnames)) - mnt_grp_dev = Device(mnt_grp) - - # TODO when we start using measurement group extension change the - # code below with the following: - # mnt_grp.setConfiguration(mnt_grp_cfg) - data = codec.encode(('', mnt_grp_cfg))[1] - mnt_grp_dev.write_attribute('configuration', data) - - @property - def _pool(self): - pooldict = self._door.macro_server.getElementsOfType('Pool') - if len(pooldict)==0: - raise ValueError('Cannot access the Pool') - elif len(pooldict)>1: - raise ValueError('Multiple pools are not supported') - poolinfo = pooldict.values()[0] - return poolinfo - + try: + mnt_grp_cfg = conf['MntGrpConfigs'][mnt_grp] + if mnt_grp_cfg is None: #a mntGrp to be deleted + pool = self._getPoolOfElement(mnt_grp) + pool.DeleteElement(mnt_grp) + else: + try: + mnt_grp_dev = Device(mnt_grp) + except: #if the mnt_grp did not already exist, create it now + chconfigs = getChannelConfigs(mnt_grp_cfg) + chnames,chinfos = zip(*chconfigs) #unzipping + pool = self._getPoolOfElement(chnames[0]) #We assume that all the channels belong to the same pool! + pool.createMeasurementGroup([mnt_grp]+list(chnames)) + mnt_grp_dev = Device(mnt_grp) + + # TODO when we start using measurement group extension change the + # code below with the following: + # mnt_grp.setConfiguration(mnt_grp_cfg) + data = codec.encode(('', mnt_grp_cfg))[1] + mnt_grp_dev.write_attribute('configuration', data) + except Exception,e: + from taurus.core.util.log import error + error('Could not create/delete/modify Measurement group "%s": %s',mnt_grp,repr(e)) + + def _getPoolOfElement(self, elementname): + ms = self._door.macro_server + einfo = ms.getElementInfo(elementname) + poolname = einfo.pool + return ms.getElementInfo(poolname) + +# @property +# def _pool(self): +# pooldict = self._door.macro_server.getElementsOfType('Pool') +# if len(pooldict)==0: +# raise ValueError('Cannot access the Pool') +# elif len(pooldict)>1: +# raise ValueError('Multiple pools are not supported') +# poolinfo = pooldict.values()[0] +# return poolinfo + class BaseDoor(MacroServerDevice): """ Class encapsulating Door device functionality.""" @@ -212,7 +255,7 @@ On = PyTango.DevState.ON Running = PyTango.DevState.RUNNING Paused = PyTango.DevState.STANDBY - + Critical = 'Critical' Error = 'Error' Warning = 'Warning' @@ -229,13 +272,12 @@ # maximum execution time without user interruption InteractiveTimeout = 0.1 - - + + def __init__(self, name, **kw): self._log_attr = CaselessDict() self._block_lines = 0 self._macro_server = None - self._running_macros = None self._running_macro = None self._last_running_macro = None @@ -245,12 +287,13 @@ 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 self._old_sw_door_state = TaurusSWDevState.Uninitialized - + self.getStateObj().addListener(self.stateChanged) for log_name in self.log_streams: @@ -261,21 +304,30 @@ 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"): @@ -292,7 +344,7 @@ BaseDoor.Debug : kls.DarkGray, BaseDoor.Result : kls.LightGreen } return self._log_start - + @property def log_stop(self): if not hasattr(self, "_log_stop"): @@ -309,10 +361,10 @@ 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: @@ -340,16 +392,16 @@ 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) @@ -366,7 +418,7 @@ if not synch: self.command_inout("AbortMacro") return - + evt_wait = AttributeEventWait(self.getAttribute("state")) evt_wait.lock() try: @@ -382,7 +434,7 @@ if not synch: self.command_inout("StopMacro") return - + evt_wait = AttributeEventWait(self.getAttribute("state")) evt_wait.lock() try: @@ -404,9 +456,9 @@ def preRunMacro(self, obj, parameters): self._clearRunMacro() - + xml_root = None - if type(obj) in types.StringTypes: + if isinstance(obj ,(str, unicode)): if obj.startswith('<') and not parameters: xml_root = etree.fromstring(obj) else: @@ -425,12 +477,12 @@ xml_macro.set('name', m[0]) xml_macro.set('id', str(uuid.uuid1())) for p in m[1]: - xml_param = etree.SubElement(xml_macro, 'param', value=p) + etree.SubElement(xml_macro, 'param', value=p) 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') @@ -439,7 +491,7 @@ 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) @@ -465,34 +517,56 @@ evt_wait.unlock() evt_wait.disconnect() return result - + def stateChanged(self, s, t, v): self._old_door_state = self.getState() self._old_sw_door_state = self.getSWState() 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: + 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 is '' and 'default_value' in input_data: + result = 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: return # make sure we get it as string since PyTango 7.1.4 returns a buffer @@ -503,7 +577,11 @@ if size == 0: return format = data[0] codec = CodecFactory().getCodec(format) - return codec.decode(data) + 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: @@ -517,7 +595,7 @@ 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]) @@ -536,7 +614,7 @@ 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 @@ -554,7 +632,7 @@ self._block_lines += 1 o += self.log_stop[log_name] self.write(o) - + def write(self, msg, stream=None): if self.isSilent(): return @@ -571,16 +649,16 @@ 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) @@ -590,7 +668,7 @@ class MacroPath(object): - + def __init__(self, ms): self._ms = weakref.ref(ms) self.refresh() @@ -602,30 +680,30 @@ class Environment(dict): - + def __init__(self, macro_server): dict.__setattr__(self, "_macro_server_", weakref.ref(macro_server)) - + def __setattr__(self, key, value): ms = self._macro_server_() if ms is not None: ms.putEnvironment(key, value) - + def __getattr__(self, key): return self[key] - + def __delattr__(self, key): ms = self._macro_server_() if ms is not None: ms.removeEnvironment(key) - + def __dir__(self): return [ key for key in self.keys() if not key.startswith("_") ] class BaseMacroServer(MacroServerDevice): """Class encapsulating Macro Server device functionality.""" - + def __init__(self, name, **kw): self._env = Environment(self) self._elements = BaseSardanaElementContainer() @@ -640,25 +718,25 @@ attr.setSerializationMode(TaurusSerializationMode.Serial) attr.addListener(self.on_environment_changed) attr.setSerializationMode(TaurusSerializationMode.Concurrent) - + NO_CLASS_TYPES = 'ControllerClass', 'ControllerLibrary', \ 'MacroLibrary', 'Instrument', 'Meta', 'ParameterType' - + def on_environment_changed(self, evt_src, evt_type, evt_value): try: return self._on_environment_changed(evt_src, evt_type, evt_value) - except Exception, e: + except Exception: self.error("Exception occurred processing environment") self.error("Details:", exc_info=1) return set(), set(), set() - + def _on_environment_changed(self, evt_src, evt_type, evt_value): ret = added, removed, changed = set(), set(), set() if evt_type not in CHANGE_EVT_TYPES: return ret - + env = CodecFactory().decode(evt_value.value) - + for key, value in env.get('new', {}).items(): self._addEnvironment(key, value) added.add(key) @@ -670,42 +748,42 @@ self._addEnvironment(key, value) changed.add(key) return ret - + def _addEnvironment(self, key, value): self._env[key] = value - + def _removeEnvironment(self, key): try: self._env.pop(key) except KeyError: pass - + def putEnvironment(self, name, value): self.putEnvironments({ name : value }) - + def putEnvironments(self, obj): obj = dict(new=obj) codec = CodecFactory().getCodec('pickle') self.write_attribute('Environment', codec.encode(('', obj))) - + setEnvironment = putEnvironment setEnvironments = putEnvironments - + def getEnvironment(self, name=None): if name is None: return self._env else: return self._env[name] - + def removeEnvironment(self, key): keys = key, return self.removeEnvironments(keys) - + def removeEnvironments(self, keys): obj = { 'del' : keys } codec = CodecFactory().getCodec('pickle') self.write_attribute('Environment', codec.encode(('', obj))) - + def getObject(self, element_info): elem_type = element_info.getType() data = element_info._data @@ -716,21 +794,21 @@ else: obj = self._createDeviceObject(element_info) return obj - + def _createMacroClassObject(self, element_info): return MacroInfo(from_json=element_info._data) - + def _createDeviceObject(self, element_info): return Factory().getDevice(element_info.full_name) - + def on_elements_changed(self, evt_src, evt_type, evt_value): try: return self._on_elements_changed(evt_src, evt_type, evt_value) - except Exception, e: + except Exception: self.error("Exception occurred processing elements") self.error("Details:", exc_info=1) return set(), set(), set() - + def _on_elements_changed(self, evt_src, evt_type, evt_value): ret = added, removed, changed = set(), set(), set() if evt_type not in CHANGE_EVT_TYPES: @@ -741,7 +819,7 @@ self.error("Could not decode element info format=%s len=%s", evt_value.value[0], len(evt_value.value[1])) return ret - + for element_data in elems.get('new', ()): element_data['manager'] = self element = self._addElement(element_data) @@ -755,51 +833,51 @@ element = self._addElement(element_data) changed.add(element) return ret - + def _addElement(self, element_data): element = BaseSardanaElement(**element_data) self.getElementsInfo().addElement(element) return element - + def _removeElement(self, element_data): name = element_data['name'] element = self.getElementInfo(name) self.getElementsInfo().removeElement(element) return element - + def getElementsInfo(self): return self._elements - + def getElements(self): return self.getElementsInfo().getElements() - + def getElementInfo(self, name): return self.getElementsInfo().getElement(name) - + def getElementNamesOfType(self, elem_type): return self.getElementsInfo().getElementNamesOfType(elem_type) - + def getElementNamesWithInterface(self, interface): return self.getElementsInfo().getElementNamesWithInterface(interface) def getElementsWithInterface(self, interface): return self.getElementsInfo().getElementsWithInterface(interface) - + def getElementsWithInterfaces(self, interfaces): return self.getElementsInfo().getElementsWithInterfaces(interfaces) - + def getElementsOfType(self, elem_type): return self.getElementsInfo().getElementsOfType(elem_type) - + def getElementsOfTypes(self, elem_types): elems = CaselessDict() for elem_type in elem_types: elems.update(self.getElementsOfType(elem_type)) return elems - + def getInterfaces(self): return self.getElementsInfo().getInterfaces() - + def getExpChannelElements(self): channel_types = "CTExpChannel", "ZeroDExpChannel", "OneDExpChannel", \ "PseudoCounter" @@ -808,7 +886,7 @@ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # Macro API #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - + def getMacros(self): return dict(self.getElementsInfo().getElementsWithInterface('MacroCode')) @@ -820,19 +898,19 @@ def getMacroStrList(self): return self.getElementNamesWithInterface('MacroCode') - + def getMacroNodeObj(self, macro_name): """ This method retrieves information about macro from MacroServer and creates MacroNode object, filled with all information about parameters. - + :param macro_name: (str) macro name - + :return: (MacroNode) - + See Also: fillMacroNodeAddidtionalInfos """ - + macroNode = MacroNode(name=macro_name) macroInfoObj = self.getMacroInfoObj(macro_name) if macroInfoObj is None: return @@ -849,7 +927,7 @@ param = ParamFactory(paramInfo) macroNode.addParam(param) return macroNode - + def validateMacroName(self, macroName): macroInfo = self.getElementInfo(macroName) if macroInfo is None: @@ -857,13 +935,13 @@ elif macroInfo.type != 'MacroClass': raise Exception("%s element is not a macro." % macroName) return True - + def validateMacroNode(self, macroNode): paramNodes = macroNode.children() for paramNode in paramNodes: self.validateParamNode(paramNode) return True - + def validateParamNode(self, paramNode): assert isinstance(paramNode, ParamNode) if isinstance(paramNode, SingleParamNode): @@ -871,12 +949,12 @@ else: self.validateRepeatParam(paramNode) return True - + def validateSingleParam(self, singleParamNode): name = singleParamNode.name() type = singleParamNode.type() value = singleParamNode.value() - + if type == "Boolean": pass elif type == "Env": @@ -890,7 +968,7 @@ elif type == "String": pass elif type == "User": - pass + pass elif type == "MotorParam": pass elif type == "Integer": @@ -917,7 +995,7 @@ if not value in allowedValues: raise Exception("%s element with %s interface does not exist in this sardana system." % (value, type)) return True - + def validateRepeatParam(self, repeatParamNode): paramName = repeatParamNode.name() if repeatParamNode.isBelowMin(): @@ -933,15 +1011,15 @@ else: self.validateRepeatParam(param) return True - - + + def fillMacroNodeAdditionalInfos(self, macroNode): """ - This method filles macroNode information which couldn't be stored + This method fills macroNode information which couldn't be stored in XML file. - + :param macroNode: (MacroNode) macro node obj populated from XML information - + See Also: getMacroNodeObj """ macroName = macroNode.name() @@ -949,7 +1027,8 @@ if macroInfoObj is None: raise Exception("It was not possible to get information about %s macro.\nCheck if MacroServer is alive and if this macro exist." % macroName) allowedHookPlaces = [] - for hook in macroInfoObj.hints.get("allowsHooks", []): + hints = macroInfoObj.hints or {} + for hook in hints.get("allowsHooks", []): allowedHookPlaces.append(str(hook)) macroNode.setAllowedHookPlaces(allowedHookPlaces) hasParams = macroInfoObj.hasParams() @@ -958,10 +1037,10 @@ paramList = macroInfoObj.getParamList() for paramNode, paramInfo in zip(macroNode.params(), paramList): self.__fillParamNodeAdditionalInfos(paramNode, paramInfo) - + def __fillParamNodeAdditionalInfos(self, paramNode, paramInfo): """ - This is a protected method foreseen to use only internally by + This is a protected method foreseen to use only internally by fillMacroNodeAdditionaInfos, to be called for every param node obj.""" type = paramInfo.get('type') paramNode.setDescription(str(paramInfo.get("description"))) @@ -977,14 +1056,14 @@ else: paramNode.setType(str(type)) paramNode.setDefValue(str(paramInfo.get("default_value"))) - + def recreateMacroNodeAndFillAdditionalInfos(self, macroNode): """ - This method filles macroNode information which couldn't be stored + This method filles macroNode information which couldn't be stored in plain text file. - + :param macroNode: (MacroNode) macro node obj populated from plain text information - + See Also: getMacroNodeObj """ macroName = macroNode.name() @@ -993,7 +1072,8 @@ if macroInfoObj is None: raise Exception("It was not possible to get information about %s macro.\nCheck if MacroServer is alive and if this macro exist." % macroName) allowedHookPlaces = [] - for hook in macroInfoObj.hints.get("allowsHooks", []): + hints = macroInfoObj.hints or {} + for hook in hints.get("allowsHooks", []): allowedHookPlaces.append(str(hook)) macroNode.setAllowedHookPlaces(allowedHookPlaces) hasParams = macroInfoObj.hasParams() @@ -1002,10 +1082,10 @@ return paramInfosList = macroInfoObj.getParamList() paramNodes = macroNode.params() - paramIndex = 0 + paramIndex = 0 for paramNode, paramInfo in zip(paramNodes, paramInfosList): paramType = paramInfo.get('type') - if isinstance(paramType,list): + if isinstance(paramType,list): paramNode = self.__recreateParamRepeatNodes(macroNode, paramIndex, paramInfo) else: paramNode.setName(paramInfo.get("name")) @@ -1020,15 +1100,15 @@ lastParam = macroNode.popParam() paramNodes.append(lastParam) paramNodes.reverse() - - nrOfSingleParams = len(paramNodes) + + nrOfSingleParams = len(paramNodes) paramName = repeatParamInfo.get("name") min = repeatParamInfo.get("min") max = repeatParamInfo.get("max") repeatParamChildrenInfos = repeatParamInfo.get("type") - + if nrOfSingleParams % len(repeatParamChildrenInfos): - raise Exception("Param repeat %s doesn't have correct number of repetitions" % paramName) + raise Exception("Param repeat %s doesn't have correct number of repetitions" % paramName) nrOfRepeats = nrOfSingleParams / len(repeatParamChildrenInfos) repeatParamNode = RepeatParamNode(macroNode, repeatParamInfo) for repeatIdx in range(nrOfRepeats): @@ -1041,18 +1121,18 @@ repeatParamNode.insertChild(repeatNode) macroNode.addParam(repeatParamNode) return repeatParamNode - + def __recreateParamNodeAdditionalInfos(self, paramNode, paramInfo): """ - This is a protected method foreseen to use only internally by + This is a protected method foreseen to use only internally by fillMacroNodeAdditionaInfos, to be called for every param node obj.""" paramType = paramInfo.get('type') min = paramInfo.get("min") max = paramInfo.get("max") paramNode.setMin(min) - paramNode.setMax(max) + paramNode.setMax(max) paramNode.setDescription(str(paramInfo.get("description"))) - + if type(paramType) == list: paramNode.setParamsInfo(paramType) for repeatNode in paramNode.children(): @@ -1061,8 +1141,8 @@ else: paramNode.setType(paramType) paramNode.setDefValue(str(paramInfo.get("default_value"))) - - + + def getMacroPathObj(self, cache=False): if not hasattr(self, "_macro_path"): self._macro_path = MacroPath(self) diff -Nru taurus-3.0.0/lib/taurus/core/tango/sardana/motion.py taurus-3.1.0/lib/taurus/core/tango/sardana/motion.py --- taurus-3.0.0/lib/taurus/core/tango/sardana/motion.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/sardana/motion.py 2013-07-25 07:53:42.000000000 +0000 @@ -31,7 +31,7 @@ import time -from taurus.core.util import CaselessDict +from taurus.core.util.containers import CaselessDict class Moveable: """ An item that can 'move'. In order to move it you need to provide a list @@ -67,6 +67,12 @@ """ generator for motor positions""" pass + def getLastMotionTime(self): + raise NotImplementedError + + def getTotalLastMotionTime(): + raise NotImplementedError + def abort(self, wait_ready=True, timeout=None): pass @@ -125,7 +131,14 @@ class MotionGroup(BaseMotion): """ A virtual motion group object """ - + + def __init__(self, elements, moveable_srcs, allow_repeat=False, + allow_unknown=False, read_only=False): + BaseMotion.__init__(self, elements, moveable_srcs, + allow_repeat=allow_repeat, + allow_unknown=allow_unknown, read_only=read_only) + self.__total_motion_time = 0 + def init_by_movables(self, elements, moveable_srcs, allow_repeat, allow_unknown): self.moveable_list = elements @@ -133,6 +146,13 @@ moveables = [ self.getMoveable(moveable_srcs, name) for name in names ] self.init_by_movables(moveables, moveable_srcs, allow_repeat, allow_unknown) + + def getLastMotionTime(self): + times = [ moveable.getLastMotionTime() for moveable in self.moveable_list ] + return max(times) + + def getTotalLastMotionTime(): + return self.__total_motion_time def startMove(self, pos_list, timeout=None): if self.read_only: @@ -153,6 +173,7 @@ moveable.waitMove(timeout=timeout, id=id[i]) def move(self, new_pos, timeout=None): + start_time = time.time() states, positions = [], [] for moveable, pos in zip(self.moveable_list, new_pos): res = moveable.move(pos, timeout=timeout) @@ -168,6 +189,7 @@ state = PyTango.DevState.UNKNOWN elif PyTango.DevState.MOVING in states: state = PyTango.DevState.MOVING + self.__total_motion_time = time.time() - start_time return state, positions def iterMove(self, new_pos, timeout=None): @@ -212,13 +234,20 @@ class Motion(BaseMotion): """ A motion object """ + + def __init__(self, elements, moveable_srcs, allow_repeat=False, + allow_unknown=False, read_only=False): + BaseMotion.__init__(self, elements, moveable_srcs, + allow_repeat=allow_repeat, + allow_unknown=allow_unknown, read_only=read_only) + self.__total_motion_time = 0 def init_by_movables(self, elements, moveable_srcs, allow_repeat, allow_unknown): # TODO: Optimize this. Dont call init_by_names. It its possible to do it # manually with some performance gain names = [ elem.getName() for elem in elements] self.init_by_names(names, moveable_srcs, allow_repeat, allow_unknown) - + def init_by_names(self, names, moveable_srcs, allow_repeat, allow_unknown): ms_elem_names = self.getElemNamesByMoveableSource(names, moveable_srcs, @@ -306,7 +335,14 @@ if moveable is None and not allow_unknown: raise Exception("Moveable item %s not found" % name) return ms_elems + + def getLastMotionTime(self): + times = [ moveable.getLastMotionTime() for moveable in self.moveable_list ] + return max(times) + def getTotalLastMotionTime(): + return self.__total_motion_time + def startMove(self, pos_list, timeout=None): if self.read_only: raise Exception("Trying to move read only motion") @@ -331,10 +367,10 @@ moveable.waitMove(timeout=timeout, id=id[i]) def move(self, new_pos, timeout=None): - #assert len(self.moveable_list) == 1, "for now we support only 'simple' motions!!!!" + start_time = time.time() if len(self.moveable_list) == 1: moveable = self.moveable_list[0] - return moveable.move(new_pos, timeout=timeout) + ret = moveable.move(new_pos, timeout=timeout) else: start, ids = 0, [] for moveable in self.moveable_list: @@ -356,7 +392,9 @@ state = PyTango.DevState.UNKNOWN elif PyTango.DevState.MOVING in states: state = PyTango.DevState.MOVING - return state, positions + ret = state, positions + self.__total_motion_time = time.time() + return ret def iterMove(self, new_pos, timeout=None): """ generator for motor positions""" diff -Nru taurus-3.0.0/lib/taurus/core/tango/sardana/pool.py taurus-3.1.0/lib/taurus/core/tango/sardana/pool.py --- taurus-3.0.0/lib/taurus/core/tango/sardana/pool.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/sardana/pool.py 2013-07-25 07:53:42.000000000 +0000 @@ -3,21 +3,21 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## @@ -38,23 +38,27 @@ import sys import os import weakref -import re -import thread import time import operator import traceback from PyTango import DevState, AttrDataFormat, AttrQuality, DevFailed, \ - DeviceProxy, AttributeProxy + DeviceProxy -from taurus import Factory -from taurus.core import TaurusEventType, AttributeNameValidator -from taurus.core.util import Logger, CaselessDict, CodecFactory, \ - EventGenerator, AttributeEventWait, AttributeEventIterator +from taurus import Factory, Device +from taurus.core.taurusbasetypes import TaurusEventType, TaurusSWDevState, \ + TaurusSerializationMode +from taurus.core.taurusvalidator import AttributeNameValidator +from taurus.core.util.log import Logger +from taurus.core.util.singleton import Singleton +from taurus.core.util.codecs import CodecFactory +from taurus.core.util.containers import CaselessDict +from taurus.core.util.event import EventGenerator, AttributeEventWait, \ + AttributeEventIterator from taurus.core.tango import TangoDevice, FROM_TANGO_TO_STR_TYPE -from sardana import BaseSardanaElementContainer, BaseSardanaElement -from motion import Moveable, MoveableSource +from .sardana import BaseSardanaElementContainer, BaseSardanaElement +from .motion import Moveable, MoveableSource Ready = Standby = DevState.ON Counting = Acquiring = Moving = DevState.MOVING @@ -84,58 +88,58 @@ pass class BaseElement(object): - """ The base class for elements in the Pool (Pool itself, Motor, + """ The base class for elements in the Pool (Pool itself, Motor, ControllerClass, ExpChannel all should inherit from this class directly or - indirectly) - - - At the object level: - self._name_lower - the lower case string name of the object (used for - __cmp__) - self._full_pool_name - the original string coming from the Pool - self._pool - the pool object + indirectly) """ - + def __repr__(self): - pd = self._pool_data + pd = self.getPoolData() return "{0}({1})".format(pd['type'], pd['full_name']) - + def __str__(self): return self.getName() - + def serialize(self): - return self._pool_data - + return self.getPoolData() + def str(self, n=0): """Returns a sequence of strings representing the object in 'consistent' way. Default is to return , , - + :param n: the number of elements in the tuple.""" if n == 0: return CodecFactory.encode(('json'), self.serialize()) return self._str_tuple[:n] - + def __cmp__(self,o): - return cmp(self._name_lower, o._name_lower) - + return cmp(self.getPoolData()['full_name'], o.getPoolData()['full_name']) + def getName(self): - return self._pool_data['name'] + return self.getPoolData()['name'] def getPoolObj(self): - return self._pool + return self._pool_obj + + def getPoolData(self): + try: + return self._pool_data + except AttributeError: + self._pool_data = self._find_pool_data() + return self._pool_data class ControllerClass(BaseElement): - + def __init__(self, **kw): self.__dict__.update(kw) - self._name_lower = self.name self.path, self.f_name = os.path.split(self.file_name) self.lib_name, self.ext = os.path.splitext(self.f_name) - + def __repr__(self): - pd = self._pool_data + pd = self.getPoolData() return "ControllerClass({0})".format(pd['full_name']) - + def getSimpleFileName(self): return self.f_name @@ -144,7 +148,7 @@ def getClassName(self): return self.getName() - + def getType(self): return self.getTypes()[0] @@ -153,13 +157,13 @@ def getLib(self): return self.f_name - + def getGender(self): return self.gender - + def getModel(self): return self.model - + def getOrganization(self): return self.organization @@ -172,10 +176,9 @@ class ControllerLib(BaseElement): - + def __init__(self, **kw): self.__dict__.update(kw) - self._name_lower = self.name def getType(self): return self.getTypes()[0] @@ -186,7 +189,7 @@ class TangoAttributeEG(Logger, EventGenerator): """An event generator for a 'State' attribute""" - + def __init__(self, attr): self._attr = attr self.call__init__(Logger, 'EG', attr) @@ -194,10 +197,10 @@ self.call__init__(EventGenerator, event_name) self._attr.addListener(self) - + def getAttribute(self): return self._attr - + def eventReceived(self, evt_src, evt_type, evt_value): """Event handler from Taurus""" if evt_type not in CHANGE_EVT_TYPES: @@ -216,18 +219,21 @@ self.debug("Details:", exc_info=1) self.last_val = None return EventGenerator.read(self) - + def readValue(self, force=False): r = self.read(force=force) if r is None: # do a retry r = self.read(force=force) return r - + + def write(self, value): + self._attr.write(value, with_read=False) + def __getattr__(self, name): return getattr(self._attr, name) - - + + def reservedOperation(fn): def new_fn(*args, **kwargs): self = args[0] @@ -246,48 +252,62 @@ return new_fn +def get_pool_for_device(db, device): + server_devs = db.get_device_class_list(device.info().server_id) + for dev_name, klass_name in zip(server_devs[0::2], server_devs[1::2]): + if klass_name == "Pool": + return Device(dev_name) + + class PoolElement(BaseElement, TangoDevice): """Base class for a Pool element device.""" - - def __init__(self, name, **kw): + + def __init__(self, name, **kwargs): """PoolElement initialization.""" self._reserved = None self._evt_wait = None - self.call__init__(TangoDevice, name, **kw) - self._name_lower = self.getName().lower() - + self.__go_start_time = 0 + self.__go_end_time = 0 + self.__go_time = 0 + self._total_go_time = 0 + self.call__init__(TangoDevice, name, **kwargs) + # dict # key : the attribute name - # value : the corresponding TangoAttributeEG + # value : the corresponding TangoAttributeEG self._attrEG = CaselessDict() - + # force the creation of a state attribute self.getStateEG() + def _find_pool_data(self): + pool = get_pool_for_device(self.getParentObj(), self.getHWObj()) + return pool.getElementInfo(self.getFullName())._data + def cleanUp(self): TangoDevice.cleanUp(self) self._reserved = None f = self.factory() - + attr_map = self._attrEG for attr_name in attr_map.keys(): attrEG = attr_map.pop(attr_name) attr = attrEG.getAttribute() attrEG = None f.removeExistingAttribute(attr) - + def reserve(self, obj): if obj is None: self._reserved = None return self._reserved = weakref.ref(obj, self._unreserveCB) - + def _unreserveCB(self, obj): self.unreserve() - + def unreserve(self): self._reserved =None - + def isReserved(self, obj=None): if obj is None: return self._reserved is not None @@ -301,18 +321,23 @@ def getReserved(self): if self._reserved is None: return None return self._reserved() - + + def dump_attributes(self): + attr_names = self.get_attribute_list() + req_id = self.read_attributes_asynch(attr_names) + return self.read_attributes_reply(req_id, 2000) + def _getAttrValue(self, name, force=False): attrEG = self._getAttrEG(name) if attrEG is None: return None return attrEG.readValue(force=force) - + def _getAttrEG(self, name): attrEG = self.getAttrEG(name) if attrEG is None: attrEG = self._createAttribute(name) return attrEG - + def _createAttribute(self, name): attrObj = self.getAttribute(name) if attrObj is None: @@ -321,34 +346,32 @@ attrEG = TangoAttributeEG(attrObj) self._attrEG[name] = attrEG return attrEG - + def _getEventWait(self): if self._evt_wait is None: # create an object that waits for attribute events. # each time we use it we have to connect and disconnect to an attribute self._evt_wait = AttributeEventWait() return self._evt_wait - + def _clearEventWait(self): self._evt_wait = None - + def getStateEG(self): return self._getAttrEG('state') - - def __cmp__(self,o): - return cmp(self._name_lower, o._name_lower) def getControllerName(self): - return self._pool_data['controller'] - + return self.getControllerObj().name + def getControllerObj(self): - return self.getPoolObj().getObj("Controller", self.getControllerName()) - + full_ctrl_name = self.getPoolData()['controller'] + return self.getPoolObj().getObj(full_ctrl_name, "Controller") + def getAxis(self): - return self._pool_data['axis'] + return self.getPoolData()['axis'] def getType(self): - return self._pool_data['type'] + return self.getPoolData()['type'] def getPoolObj(self): return self._pool_obj @@ -359,9 +382,9 @@ def getAttrEG(self, name): """Returns the TangoAttributeEG object""" return self._attrEG.get(name) - + def getAttrObj(self, name): - """Returns the taurus.core.TangoAttribute object""" + """Returns the taurus.core.tangoattribute.TangoAttribute object""" attrEG = self._attrEG.get(name) if attrEG is None: return None @@ -369,18 +392,18 @@ def getInstrumentObj(self): return self._getAttrEG('instrument') - + def getInstrumentName(self, force=False): instr_name = self._getAttrValue('instrument', force=force) if not instr_name: return '' #instr_name = instr_name[:instr_name.index('(')] return instr_name - + def getInstrument(self): instr_name = self.getInstrumentName() if not instr_name: return None return self.getPoolObj().getObj("Instrument", instr_name) - + @reservedOperation def start(self, *args, **kwargs): evt_wait = self._getEventWait() @@ -388,7 +411,8 @@ evt_wait.lock() try: evt_wait.waitEvent(DevState.MOVING, equal=False) - ts1 = time.time() + self.__go_time = 0 + self.__go_start_time = ts1 = time.time() self._start(*args, **kwargs) ts2 = time.time() evt_wait.waitEvent(DevState.MOVING, after=ts1) @@ -410,14 +434,28 @@ evt_wait.waitEvent(DevState.MOVING, after=id, equal=False, timeout=timeout) finally: + self.__go_end_time = time.time() + self.__go_time = self.__go_end_time - self.__go_start_time evt_wait.unlock() evt_wait.disconnect() @reservedOperation def go(self, *args, **kwargs): - id = self.start(*args, **kwargs) - self.waitFinish(id=id) - + self._total_go_time = 0 + start_time = time.time() + eid = self.start(*args, **kwargs) + self.waitFinish(id=eid) + self._total_go_time = time.time() - start_time + + def getLastGoTime(self): + """Returns the time it took for last go operation""" + return self.__go_time + + def getTotalLastGoTime(self): + """Returns the time it took for last go operation, including dead time + to prepare, wait for events, etc""" + return self._total_go_time + def abort(self, wait_ready=True, timeout=None): state = self.getStateEG() state.lock() @@ -437,11 +475,11 @@ self.waitReady(timeout=timeout) finally: state.unlock() - + def information(self, tab=' '): msg = self._information(tab=tab) return "\n".join(msg) - + def _information(self, tab=' '): indent = "\n" + tab + 10*' ' msg = [ self.getName() + ":" ] @@ -472,7 +510,7 @@ e_info = sys.exc_info()[:2] status = traceback.format_exception_only(*e_info) msg.append(tab + " Status: " + status) - + return msg @@ -484,54 +522,54 @@ self.call__init__(PoolElement, name, **kw) def getModuleName(self): - return self._pool_data['module'] - + return self.getPoolData()['module'] + def getClassName(self): - return self._pool_data['klass'] - + return self.getPoolData()['klass'] + def getTypes(self): - return self._pool_data['types'] - + return self.getPoolData()['types'] + def getMainType(self): - return self._pool_data['main_type'] - + return self.getPoolData()['main_type'] + def addElement(self, elem): axis = elem.getAxis() self._elems[axis] = elem self._last_axis = max(self._last_axis, axis) - + def removeElement(self, elem): axis = elem.getAxis() del self._elems[elem.getAxis()] if axis == self._last_axis: self._last_axis = max(self._elems) - + def getElementByAxis(self, axis): pool = self.getPoolObj() - for name, elem in pool.getElementsOfType(self.getMainType()).items(): + for _, elem in pool.getElementsOfType(self.getMainType()).items(): if elem.controller != self.getName() or elem.getAxis() != axis: continue return elem - + def getElementByName(self, name): pool = self.getPoolObj() for name, elem in pool.getElementsOfType(self.getMainType()).items(): if elem.controller != self.getName() or elem.getName() != name: continue return elem - + def getUsedAxis(self): pool = self.getPoolObj() axis = [] - for name, elem in pool.getElementsOfType(self.getMainType()).items(): + for _, elem in pool.getElementsOfType(self.getMainType()).items(): if elem.controller != self.getName(): continue axis.append(elem.getAxis()) return sorted(axis) - + def getLastUsedAxis(self): return max([1] + self.getUsedAxis()) - + def __cmp__(self, o): return cmp(self.getName(), o.getName()) @@ -584,7 +622,7 @@ def getDialPosition(self, force=False): return self._getAttrValue('dialposition', force=force) - + def getVelocity(self, force=False): return self._getAttrValue('velocity', force=force) @@ -593,7 +631,7 @@ def getDeceleration(self, force=False): return self._getAttrValue('deceleration', force=force) - + def getBaseRate(self, force=False): return self._getAttrValue('base_rate', force=force) @@ -602,16 +640,16 @@ def getLimitSwitches(self, force=False): return self._getAttrValue('limit_switches', force=force) - + def getOffset(self, force=False): return self._getAttrValue('offset', force=force) - + def getStepPerUnit(self, force=False): return self._getAttrValue('step_per_unit', force=force) - + def getSign(self, force=False): return self._getAttrValue('Sign', force=force) - + def getSimulationMode(self, force=False): return self._getAttrValue('SimulationMode', force=force) @@ -629,7 +667,7 @@ def getDecelerationObj(self): return self._getAttrEG('deceleration') - + def getBaseRateObj(self): return self._getAttrEG('base_rate') @@ -638,20 +676,44 @@ def getLimitSwitchesObj(self): return self._getAttrEG('limit_switches') - + def getOffsetObj(self): return self._getAttrEG('offset') - + def getStepPerUnitObj(self): return self._getAttrEG('step_per_unit') - + def getSimulationModeObj(self): return self._getAttrEG('step_per_unit') + def setVelocity(self, value): + return self.getVelocityObj().write(value) + + def setAcceleration(self, value): + return self.getAccelerationObj().write(value) + + def setDeceleration(self, value): + return self.getDecelerationObj().write(value) + + def setBaseRate(self, value): + return self.getBaseRateObj().write(value) + + def setBacklash(self, value): + return self.getBacklashObj().write(value) + + def setOffset(self, value): + return self.getOffsetObj().write(value) + + def setStepPerUnit(self, value): + return self.getStepPerUnitObj().write(value) + + def setSign(self, value): + return self.getSignObj().write(value) + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # Moveable interface # - + def _start(self, *args, **kwargs): new_pos = args[0] if operator.isSequenceType(new_pos): @@ -667,13 +729,18 @@ self.final_pos = new_pos def go(self, *args, **kwargs): + start_time = time.time() PoolElement.go(self, *args, **kwargs) - return self.getStateEG().readValue(), self.readPosition() - + ret = self.getStateEG().readValue(), self.readPosition() + self._total_go_time = time.time() - start_time + return ret + startMove = PoolElement.start waitMove = PoolElement.waitFinish move = go - + getLastMotionTime = PoolElement.getLastGoTime + getTotalLastMotionTime = PoolElement.getTotalLastGoTime + @reservedOperation def iterMove(self, new_pos, timeout=None): if operator.isSequenceType(new_pos): @@ -701,7 +768,7 @@ finally: evt_wait.unlock() evt_wait.disconnect() - + evt_iter_wait = AttributeEventIterator(state, pos) evt_iter_wait.lock() try: @@ -713,18 +780,18 @@ finally: evt_iter_wait.unlock() evt_iter_wait.disconnect() - + def readPosition(self, force=False): return [ self.getPosition(force=force) ] - + def getMoveableSource(self): return self.getPoolObj() def getSize(self): return 1 - + def getIndex(self, name): - if name.lower() == self._name_lower: + if name.lower() == self.getName().lower(): return 0 return -1 # @@ -791,24 +858,29 @@ self.final_pos = new_pos def go(self, *args, **kwargs): + start_time = time.time() PoolElement.go(self, *args, **kwargs) - return self.getStateEG().readValue(), self.readPosition() - + ret = self.getStateEG().readValue(), self.readPosition() + self._total_go_time = time.time() - start_time + return ret + startMove = PoolElement.start waitMove = PoolElement.waitFinish move = go + getLastMotionTime = PoolElement.getLastGoTime + getTotalLastMotionTime = PoolElement.getTotalLastGoTime def readPosition(self, force=False): return [ self.getPosition(force=force) ] - + def getMoveableSource(self): return self.getPoolObj() def getSize(self): return 1 - + def getIndex(self, name): - if name.lower() == self._name_lower: + if name.lower() == self.getName().lower(): return 0 return -1 # @@ -846,14 +918,14 @@ def _create_str_tuple(self): return 3*["TODO"] - + def getMotorNames(self): - return self._pool_data['elements'] - + return self.getPoolData()['elements'] + def hasMotor(self, name): motor_names = map(str.lower, self.getMotorNames()) return name.lower() in motor_names - + def getPosition(self, force=False): return self._getAttrValue('position', force=force) @@ -877,32 +949,37 @@ self.final_pos = new_pos def go(self, *args, **kwargs): + start_time = time.time() PoolElement.go(self, *args, **kwargs) - return self.getStateEG().readValue(), self.readPosition() - + ret = self.getStateEG().readValue(), self.readPosition() + self._total_go_time = time.time() - start_time + return ret + startMove = PoolElement.start waitMove = PoolElement.waitFinish move = go - + getLastMotionTime = PoolElement.getLastGoTime + getTotalLastMotionTime = PoolElement.getTotalLastGoTime + def readPosition(self, force=False): return self.getPosition(force=force) - + def getMoveableSource(self): return self.getPoolObj() def getSize(self): return len(self.getMotorNames()) - + def getIndex(self, name): try: motor_names = map(str.lower, self.getMotorNames()) return motor_names.index(name.lower()) except: return -1 - + # # End of Moveable interface - #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def _information(self, tab=' '): msg = PoolElement._information(self, tab=tab) @@ -920,13 +997,13 @@ except: e_info = sys.exc_info()[:2] pos = traceback.format_exception_only(*e_info) - + msg.append(tab + "Position: " + str(pos)) return msg class BaseChannelInfo(object): - + def __init__(self, data): # dict # channel data @@ -935,15 +1012,26 @@ class TangoChannelInfo(BaseChannelInfo): - + def __init__(self, data, info): BaseChannelInfo.__init__(self, data) # PyTango.AttributeInfoEx + self.set_info(info) + + def has_info(self): + return self.raw_info is not None + + def set_info(self, info): self.raw_info = info + if info is None: + return + + data = self.raw_data + if 'data_type' not in data: self.data_type = FROM_TANGO_TO_STR_TYPE[info.data_type] - + if 'shape' not in data: shape = () if info.data_format == AttrDataFormat.SPECTRUM: @@ -951,9 +1039,15 @@ elif info.data_format == AttrDataFormat.IMAGE: shape = (info.max_dim_x, info.max_dim_y) self.shape = shape + else: + shape = self.shape + self.shape = list(shape) def __getattr__(self, name): - return getattr(self.raw_info, name) + if self.has_info(): + return getattr(self.raw_info, name) + cls_name = self.__class__.__name__ + raise AttributeError("'%s' has no attribute '%s'" % (cls_name, name)) def getChannelConfigs(mgconfig, ctrls=None, units=None, sort=True): @@ -962,16 +1056,16 @@ units levels of the given measurement group configuration. It optionally filters to those channels matching given lists of controller and unit names. - - :param ctrls: (seq or None) a sequence of strings to filter the + + :param ctrls: (seq or None) a sequence of strings to filter the controllers. If None given, all controllers will be used - :param units: (seq) a sequence of strings to filter the units. If + :param units: (seq) a sequence of strings to filter the units. If None given, all controllers will be used :param sort: (bool) If True (default) the returned list will be sorted according to channel index (if given in channeldata) and then by channelname. - - :return: (list) A list of channelname,channeldata pairs. + + :return: (list) A list of channelname,channeldata pairs. ''' chconfigs = [] if not mgconfig: return [] @@ -983,42 +1077,41 @@ ch_data.update({'_controller_name':ctrl_name, '_unit_id':unit_id}) #add controller and unit ids chconfigs.append((ch_name,ch_data)) if sort: - #sort the channel configs by index (primary sort) and then by channel name. + #sort the channel configs by index (primary sort) and then by channel name. chconfigs = sorted(chconfigs, key=lambda c:c[0]) #sort by channel_name chconfigs = sorted(chconfigs, key=lambda c:c[1].get('index',1e16)) #sort by index (give a very large index for those which don't have it) return chconfigs class MGConfiguration(object): - + def __init__(self, mg, data): self._mg = weakref.ref(mg) if isinstance(data, (str, unicode)): data = CodecFactory().decode(('json', data), ensure_ascii=True) self.raw_data = data self.__dict__.update(data) - + # dict # where key is the channel name and value is the channel data in form - # of a dict as receveid by the MG configuration attribute + # of a dict as receveid by the MG configuration attribute self.channels = channels = CaselessDict() - - for ctrl_name, ctrl_data in self.controllers.items(): - for unit_id, unit_data in ctrl_data['units'].items(): + + for _, ctrl_data in self.controllers.items(): + for _, unit_data in ctrl_data['units'].items(): for channel_name, channel_data in unit_data['channels'].items(): - data_source = channel_data['source'] channels[channel_name] = channel_data - + ##################### #@todo: the for-loops above could be replaced by something like: - #self.channels = channels = CaselessDict(getChannelConfigs(data,sort=False)) + #self.channels = channels = CaselessDict(getChannelConfigs(data,sort=False)) ##################### - + # seq each element is the channel data in form of a dict as # receveid by the MG configuration attribute. This seq is just a cache # ordered by channel index in the MG. - self.channel_list = channel_list = len(channels)*[None] - + self.channel_list = len(channels)*[None] + for channel in channels.values(): self.channel_list[channel['index']] = channel @@ -1028,11 +1121,11 @@ # - A dict where keys are attribute names and value is a reference to # a dict representing channel data as received in raw data self.tango_dev_channels = None - - # Number of elements in tango_dev_channels in error (could not build + + # Number of elements in tango_dev_channels in error (could not build # DeviceProxy, probably) self.tango_dev_channels_in_error = 0 - + # dict> # where key is a channel name and value is a tuple of three elements: # - device name @@ -1044,14 +1137,14 @@ # Number of elements in tango_channels_info_in_error in error # (could not build attribute info, probably) self.tango_channels_info_in_error = 0 - + # dict # where key is a channel name and data is a reference to a dict # representing channel data as received in raw data self.non_tango_channels = None - + self.initialized = False - + def _build(self): # internal channel structure that groups channels by tango device so # they can be read as a group minimizing this way the network requests @@ -1061,11 +1154,12 @@ self.tango_channels_info_in_error = 0 self.non_tango_channels = n_tg_chs = CaselessDict() self.cache = cache = {} - + tg_attr_validator = AttributeNameValidator() for channel_name, channel_data in self.channels.items(): cache[channel_name] = None data_source = channel_data['source'] + #external = ctrl_name.startswith("__") params = tg_attr_validator.getParams(data_source) if params is None: # Handle NON tango channel @@ -1078,7 +1172,7 @@ if host is not None and port is not None: dev_name = "{0}:{1}/{2}".format(host, port, dev_name) dev_data = tg_dev_chs.get(dev_name) - + if dev_data is None: # Build tango device dev = None @@ -1089,7 +1183,7 @@ tg_dev_chs[dev_name] = dev_data = [ dev, CaselessDict() ] dev, attr_data = dev_data attr_data[attr_name] = channel_data - + # get attribute configuration attr_info = None if dev is None: @@ -1097,18 +1191,26 @@ else: try: tg_attr_info = dev.get_attribute_config_ex(attr_name)[0] - attr_info = TangoChannelInfo(channel_data, tg_attr_info) except: - import traceback - traceback.print_exc() + tg_attr_info = \ + self._build_empty_tango_attr_info(channel_data) self.tango_channels_info_in_error += 1 + attr_info = TangoChannelInfo(channel_data, tg_attr_info) + tg_chs_info[channel_name] = dev_name, attr_name, attr_info + def _build_empty_tango_attr_info(self, channel_data): + import PyTango + ret = PyTango.AttributeInfoEx() + ret.name = channel_data['name'] + ret.label = channel_data['label'] + return ret + def prepare(self): # first time? build everything if self.tango_dev_channels is None: return self._build() - + # prepare missing tango devices if self.tango_dev_channels_in_error > 0: for dev_name, dev_data in self.tango_dev_channels.items(): @@ -1118,57 +1220,77 @@ self.tango_dev_channels_in_error -= 1 except: pass - + # prepare missing tango attribute configuration if self.tango_channels_info_in_error > 0: - for channel_name, attr_data in self.tango_channels_info.items(): + for _, attr_data in self.tango_channels_info.items(): dev_name, attr_name, attr_info = attr_data - if attr_info is not None: + if attr_info.has_info(): continue dev = self.tango_dev_channels[dev_name] if dev is None: continue try: tg_attr_info = dev.get_attribute_config_ex(attr_name)[0] - channel_data = self.channels[channel_name] - attr_info = attr_info = TangoChannelInfo(channel_data, tg_attr_info) - attr_data[2] = attr_info + attr_info.set_info(tg_attr_info) self.tango_channels_info_in_error -= 1 except: - continue - + pass + def getChannelInfo(self, channel_name): - return self.tango_channels_info[channel_name] - + try: + return self.tango_channels_info[channel_name] + except: + channel_name = channel_name.lower() + for d_name, a_name, ch_info in self.tango_channels_info.values(): + if ch_info.name.lower() == channel_name: + return d_name, a_name, ch_info + def getChannelsInfo(self): self.prepare() - return self.tango_channels_info - + ret = CaselessDict(self.tango_channels_info) + ret.update(self.non_tango_channels) + return ret + def getChannelsInfoList(self): - ch_info = self.getChannelsInfo() - return [ ch_info[ch['name']][2] for ch in self.channel_list ] - - def getCountersInfoList(self): - ch_info = self.getChannelsInfo() - ret = [] - for ch in self.channel_list: - ch_name = ch['name'] - if ch_name != self.timer: - ret.append(ch_info[ch_name][2]) + channels_info = self.getChannelsInfo() + ret = len(channels_info)*[None] + for _, (_,_,ch_info) in channels_info.items(): + ret[ch_info.index] = ch_info return ret + + def getCountersInfoList(self): + channels_info = self.getChannelsInfoList() + timer_name, idx = self.timer, -1 + for i, ch in enumerate(channels_info): + if ch['full_name'] == timer_name: + idx = i + break + if idx >= 0: + channels_info.pop(idx) + return channels_info + + def read(self, parallel=True): + if parallel: + return self._read_parallel() + return self._read() - def read_parallel(self): + def _read_parallel(self): self.prepare() ret = CaselessDict(self.cache) dev_replies = {} - for dev_name, dev_data in self.tango_dev_channels.items(): + + # deposit read requests + for _, dev_data in self.tango_dev_channels.items(): dev, attrs = dev_data if dev is None: continue try: dev_replies[dev] = dev.read_attributes_asynch(attrs.keys()), attrs except: - continue + dev_replies[dev] = None, attrs + + # gather all replies for dev, reply_data in dev_replies.items(): reply, attrs = reply_data try: @@ -1179,15 +1301,17 @@ value = None else: value = data_item.value - ret[channel_data['name']] = value + ret[channel_data['full_name']] = value except: - continue + for _, channel_data in attrs.items(): + ret[channel_data['full_name']] = None + return ret - def read(self): + def _read(self): self.prepare() ret = CaselessDict(self.cache) - for dev_name, dev_data in self.tango_dev_channels.items(): + for _, dev_data in self.tango_dev_channels.items(): dev, attrs = dev_data try: data = dev.read_attributes(attrs.keys()) @@ -1197,51 +1321,53 @@ value = None else: value = data_item.value - ret[channel_data['name']] = value + ret[channel_data['full_name']] = value except: - continue + for _, channel_data in attrs.items(): + ret[channel_data['full_name']] = None return ret class MeasurementGroup(PoolElement): """ Class encapsulating MeasurementGroup functionality.""" - + def __init__(self, name, **kw): """PoolElement initialization.""" self._configuration = None self._channels = None + self._last_integ_time = None self.call__init__(PoolElement, name, **kw) - + cfg_attr = self.getAttribute('configuration') cfg_attr.addListener(self.on_configuration_changed) def _create_str_tuple(self): return self.getName(), self.getTimerName(), ", ".join(self.getChannelNames()) - + def getConfigurationAttrEG(self): return self._getAttrEG('Configuration') - + def setConfiguration(self, configuration): data = CodecFactory().encode(('json', configuration)) self.write_attribute('configuration', data) - + def _setConfiguration(self, data): self._configuration = MGConfiguration(self, data) - + def getConfiguration(self, force=False): if force or self._configuration is None: data = self.getConfigurationAttrEG().readValue(force=True) self._setConfiguration(data) return self._configuration - + def on_configuration_changed(self, evt_src, evt_type, evt_value): if evt_type not in CHANGE_EVT_TYPES: return self.info("Configuration changed") self._setConfiguration(evt_value.value) - + def getTimerName(self): - return self.getConfiguration().timer - + return self.getTimer()['name'] + def getTimer(self): cfg = self.getConfiguration() return cfg.channels[cfg.timer] @@ -1250,7 +1376,7 @@ return self.getTimerName() def getMonitorName(self): - return self.getConfiguration().monitor + return self.getMonitor()['name'] def getMonitor(self): cfg = self.getConfiguration() @@ -1258,7 +1384,7 @@ def setTimer(self, timer_name): try: - channel = self.getChannel(timer_name) + self.getChannel(timer_name) except KeyError: raise Exception("%s does not contain a channel named '%s'" % (str(self),timer_name)) @@ -1266,58 +1392,72 @@ cfg['timer'] = timer_name import json self.write_attribute("configuration", json.dumps(cfg)) - + def getChannels(self): return self.getConfiguration().channel_list - + def getCounters(self): cfg = self.getConfiguration() - return [ ch for ch in self.getChannels() if ch['name'] != cfg.timer ] - + return [ ch for ch in self.getChannels() if ch['full_name'] != cfg.timer ] + def getChannelNames(self): return [ ch['name'] for ch in self.getChannels() ] - + def getCounterNames(self): - cfg = self.getConfiguration() return [ ch['name'] for ch in self.getCounters() ] - + + def getChannelLabels(self): + return [ ch['label'] for ch in self.getChannels() ] + + def getCounterLabels(self): + return [ ch['label'] for ch in self.getCounters() ] + def getChannel(self, name): return self.getConfiguration().channels[name] - + def getChannelInfo(self, name): return self.getConfiguration().getChannelInfo(name) - + def getChannelsInfo(self): return self.getConfiguration().getChannelsInfoList() - + def getCountersInfo(self): return self.getConfiguration().getCountersInfoList() - - def getValues(self): - return self.getConfiguration().read() - + + def getValues(self, parallel=True): + return self.getConfiguration().read(parallel=parallel) + def getIntegrationTime(self): return self._getAttrValue('IntegrationTime') - + def getIntegrationTimeObj(self): return self._getAttrEG('IntegrationTime') - + def setIntegrationTime(self, ctime): self.getIntegrationTimeObj().write(ctime) - + + def putIntegrationTime(self, ctime): + if self._last_integ_time == ctime: + return + self._last_integ_time = ctime + self.getIntegrationTimeObj().write(ctime) + def _start(self, *args, **kwargs): self.Start() - + def go(self, *args, **kwargs): + start_time = time.time() cfg = self.getConfiguration() cfg.prepare() duration = args[0] if duration is None or duration == 0: return self.getStateEG().readValue(), self.getValues() - self.setIntegrationTime(duration) + self.putIntegrationTime(duration) PoolElement.go(self, *args, **kwargs) - return self.getStateEG().readValue(), self.getValues() - + ret = self.getStateEG().readValue(), self.getValues() + self._total_go_time = time.time() - start_time + return ret + startCount = PoolElement.start waitCount = PoolElement.waitFinish count = go @@ -1333,10 +1473,10 @@ def getValueObj(self): return self._getAttrEG('value') - + def readValue(self, force=False): return self._getAttrValue('value', force=force) - + def startWriteValue(self, new_value, timeout=None): try: self.getValueObj().write(new_value) @@ -1347,10 +1487,10 @@ raise RuntimeError, '%s is already chaging' % self else: raise - + def waitWriteValue(self, timeout=None): pass - + def writeValue(self, new_value, timeout=None): self.startWriteValue(new_value, timeout=timeout) self.waitWriteValue(timeout=timeout) @@ -1361,24 +1501,23 @@ class Instrument(BaseElement): - + def __init__(self, **kw): self.__dict__.update(kw) - self._name_lower = self.full_name.lower() - + def getFullName(self): return self.full_name - + def getParentInstrument(self): return self.getPoolObj().getObj(self.parent_instrument) def getParentInstrumentName(self): return self.parent_instrument - + def getChildrenInstruments(self): raise NotImplementedError return self._children - + def getElements(self): raise NotImplementedError return self._elements @@ -1392,14 +1531,14 @@ class Pool(TangoDevice, MoveableSource): """ Class encapsulating device Pool functionality.""" - + def __init__(self, name, **kw): self.call__init__(TangoDevice, name, **kw) self.call__init__(MoveableSource) - + self._elements = BaseSardanaElementContainer() self.getAttribute("Elements").addListener(self.on_elements_changed) - + def getObject(self, element_info): elem_type = element_info.getType() data = element_info._data @@ -1407,11 +1546,12 @@ klass = globals()[elem_type] kwargs = dict(data) kwargs['_pool_data'] = data + kwargs['_pool_obj'] = self return klass(**kwargs) obj = Factory().getDevice(element_info.full_name, _pool_obj=self, _pool_data=data) return obj - + def on_elements_changed(self, evt_src, evt_type, evt_value): if evt_type == TaurusEventType.Error: msg = evt_value @@ -1443,30 +1583,34 @@ elements.addElement(element) for element_data in elems.get('del', ()): element = self.getElementInfo(element_data['name']) - elements.removeElement(element) + try: + elements.removeElement(element) + except: + self.warning("Failed to remove %s", element_data) + return elems - + def getElementsInfo(self): return self._elements - + def getElements(self): return self.getElementsInfo().getElements() - + def getElementInfo(self, name): return self.getElementsInfo().getElement(name) - + def getElementNamesOfType(self, elem_type): return self.getElementsInfo().getElementNamesOfType(elem_type) - + def getElementsOfType(self, elem_type): return self.getElementsInfo().getElementsOfType(elem_type) - + def getElementsWithInterface(self, interface): return self.getElementsInfo().getElementsWithInterface(interface) - + def getElementWithInterface(self, elem_name, interface): return self.getElementsInfo().getElementWithInterface(elem_name, interface) - + def getObj(self, name, elem_type=None): if elem_type is None: return self.getElementInfo(name) @@ -1474,12 +1618,16 @@ elem_types = elem_type, else: elem_types = elem_type + name = name.lower() for e_type in elem_types: elems = self.getElementsOfType(e_type) + for elem in elems.values(): + if elem.name.lower() == name: + return elem elem = elems.get(name) if elem is not None: return elem - + def __repr__(self): return self.getNormalName() @@ -1488,37 +1636,42 @@ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # MoveableSource interface - # - + # + def getMoveable(self, names): """getMoveable(seq names) -> Moveable - Returns a moveable object that handles all the moveable items given in + Returns a moveable object that handles all the moveable items given in names.""" # if simple motor just return it (if the pool has it) if isinstance(names, (str, unicode)): names = names, - + if len(names) == 1: name = names[0] return self.getObj(name, elem_type=MOVEABLE_TYPES) - + # find a motor group that contains elements moveable = self.__findMotorGroupWithElems(names) - + # if none exists create one if moveable is None: mgs = self.getElementsOfType('MotorGroup') - i, cont = 1, True + i = 1 pid = os.getpid() - while cont: + while True: name = "_mg_ms_{0}_{1}".format(pid, i) - if name not in mgs: - cont = False + exists = False + for mg in mgs.values(): + if mg.name == name: + exists = True + break + if not exists: + break i += 1 moveable = self.createMotorGroup(name, names) return moveable - + def __findMotorGroupWithElems(self, names): names_lower = map(str.lower, names) len_names = len(names) @@ -1532,11 +1685,11 @@ break else: return mg - + # # End of MoveableSource interface #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - + def _wait_for_element_in_container(self, container, elem_name, timeout=0.5, contains=True): start = time.time() @@ -1559,24 +1712,24 @@ elem_name) return time.sleep(nap) - + def createMotorGroup(self, mg_name, elements): params = [mg_name,] + map(str, elements) self.debug('trying to create motor group for elements: %s', params) self.command_inout('CreateMotorGroup', params) elements_info = self.getElementsInfo() return self._wait_for_element_in_container(elements_info, mg_name) - + def createMeasurementGroup(self, mg_name, elements): params = [mg_name,] + map(str,elements) self.debug('trying to create measurement group: %s', params) self.command_inout('CreateMeasurementGroup', params) elements_info = self.getElementsInfo() return self._wait_for_element_in_container(elements_info, mg_name) - + def deleteMeasurementGroup(self, name): return self.deleteElement(name) - + def createElement(self, name, ctrl, axis=None): ctrl_type = ctrl.types[0] if axis is None: @@ -1588,14 +1741,14 @@ self.command_inout(cmd, pars) elements_info = self.getElementsInfo() return self._wait_for_element_in_container(elements_info, name) - + def deleteElement(self, name): self.debug('trying to delete element: %s', name) self.command_inout('DeleteElement', name) elements_info = self.getElementsInfo() return self._wait_for_element_in_container(elements_info, name, contains=False) - + def createController(self, class_name, name, *props): ctrl_class = self.getObj(class_name, elem_type='ControllerClass') if ctrl_class is None: @@ -1606,7 +1759,7 @@ self.command_inout(cmd, pars) elements_info = self.getElementsInfo() return self._wait_for_element_in_container(elements_info, name) - + def deleteController(self, name): return self.deleteElement(name) @@ -1614,14 +1767,14 @@ def registerExtensions(): factory = Factory() factory.registerDeviceClass("Pool", Pool) - + hw_type_names = [ 'Controller', 'ComChannel', 'Motor', 'PseudoMotor', 'CTExpChannel','ZeroDExpChannel','OneDExpChannel', 'TwoDExpChannel', 'PseudoCounter', 'IORegister', 'MotorGroup', 'MeasurementGroup'] - + hw_type_map = [ (name, globals()[name]) for name in hw_type_names ] - + for klass_name, klass in hw_type_map: factory.registerDeviceClass(klass_name, klass) diff -Nru taurus-3.0.0/lib/taurus/core/tango/sardana/sardana.py taurus-3.1.0/lib/taurus/core/tango/sardana/sardana.py --- taurus-3.0.0/lib/taurus/core/tango/sardana/sardana.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/sardana/sardana.py 2013-07-25 07:53:42.000000000 +0000 @@ -3,21 +3,21 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## @@ -39,21 +39,21 @@ __docformat__ = 'restructuredtext' -import socket - -import time import PyTango -from taurus.core.util import Enumeration, Singleton, Logger, CaselessDict, \ - CodecFactory +from taurus.core.util.enumeration import Enumeration +from taurus.core.util.log import Logger +from taurus.core.util.singleton import Singleton +from taurus.core.util.containers import CaselessDict +from taurus.core.util.codecs import CodecFactory PoolElementType = Enumeration("PoolElementType", - ("0D", "1D", "2D", "Communication", "CounterTimer", "IORegister", + ("0D", "1D", "2D", "Communication", "CounterTimer", "IORegister", "Motor","PseudoCounter", "PseudoMotor")) -ChannelView = Enumeration("ChannelView", - ("Channel", "Enabled", "Output", "PlotType", "PlotAxes", "Timer", - "Monitor", "Trigger", "Conditioning", "Normalization","NXPath", +ChannelView = Enumeration("ChannelView", + ("Channel", "Enabled", "Output", "PlotType", "PlotAxes", "Timer", + "Monitor", "Trigger", "Conditioning", "Normalization","NXPath", "Shape", "DataType", "Unknown")) @@ -64,7 +64,7 @@ #: an enumeration describing all possible acquisition trigger types AcqTriggerType = Enumeration("AcqTriggerType", ( \ "Software", # channel triggered by software - start and stop by software - "Gate", # channel triggered by HW - start and stop by external + "Gate", # channel triggered by HW - start and stop by external "Unknown") ) #: an enumeration describing all possible acquisition mode types @@ -76,113 +76,113 @@ class BaseSardanaElement(object): """Generic sardana element""" - + def __init__(self, *args, **kwargs): self._manager = kwargs.pop('manager') self.__dict__.update(kwargs) self._data = kwargs self._object = None - + def __repr__(self): return "{0}({1})".format(self.type, self.full_name) - + def __str__(self): return self.name - + def __getattr__(self, name): return getattr(self.getObj(), name) - + def __cmp__(self, elem): return cmp(self.name, elem.name) - + def getData(self): return self._data - + def getName(self): return self.name - + def getId(self): return self.full_name - + def getType(self): return self.getTypes()[0] - + def getTypes(self): elem_types = self.type if isinstance(elem_types, (str, unicode)): return [elem_types] return elem_types - + def serialize(self, *args, **kwargs): kwargs.update(self._data) return kwargs - + def str(self, *args, **kwargs): #TODO change and check which is the active protocol to serialize #acordingly return CodecFactory().encode(('json', self.serialize(*args, **kwargs))) - + def getObj(self): obj = self._object if obj is None: self._object = obj = self._manager.getObject(self) return obj - + class BaseSardanaElementContainer: - + def __init__(self): # dict where key is the type and value is: - # dict where key is the element alias and - # value is the Element object + # dict where key is the element full name + # and value is the Element object self._type_elems_dict = CaselessDict() - + # dict 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_name = elem.getName() - + 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_name] = elem - + 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_name] = elem - + interface_elems[elem_full_name] = elem + def removeElement(self, e): - type = e.getType() - + elem_type = e.getType() + # update type_elems - type_elems = self._type_elems_dict.get(type) + type_elems = self._type_elems_dict.get(elem_type) if type_elems: - del type_elems[e.name] - + del type_elems[e.full_name] + # update interfaces for interface in e.interfaces: interface_elems = self._interfaces_dict.get(interface) - del interface_elems[e.name] - + 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() ] - + return [e.name for e in self.getElementsOfType(t).values()] + def getElementsWithInterface(self, interface): elems = self._interfaces_dict.get(interface, {}) return elems @@ -194,32 +194,42 @@ return ret def getElementNamesWithInterface(self, interface): - return [ e.name for e in self.getElementsWithInterface(interface).values() ] - + return [e.name for e in self.getElementsWithInterface(interface).values()] + def hasElementName(self, elem_name): return self.getElement(elem_name) != None - + def getElement(self, elem_name): + elem_name = elem_name.lower() for elems in self._type_elems_dict.values(): - elem = elems.get(elem_name) + 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): - return self._interfaces_dict.get(interface, {}).get(elem_name) - + 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 - + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # T E M P O R A R Y I M P L E M E N T A T I O N # @@ -231,19 +241,19 @@ self._type = type self._format = format self._default_value=default_value - + def get_name(self): return self._name def get_type(self): return self._type - + def get_format(self): return self._format - + def get_default_value(self): return self._default_value - + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # T E M P O R A R Y I M P L E M E N T A T I O N @@ -251,32 +261,32 @@ # THIS IS USED FOR TEST PURPOSES ONLY. DO NOT USE IT OUTSIDE SARDANA TESTS #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class ControllerClassInfo(object): - + def __init__(self, name, type, library): self._name = name self._type = type self._library = library - + def get_max_elements(self): return 20 - + def get_name(self): return self._name - + def get_model(self): # fake data ############### - return "Model of "+ self._name - + return "Model of "+ self._name + def get_icon(self): # fake data ############### import taurus.qt.qtgui.resource - + return taurus.qt.qtgui.resource.getIcon(":/designer/extra_motor.png") - + def get_organization(self): # fake data ############### - return "Organization of "+ self._name - + return "Organization of "+ self._name + def get_description(self): #fake data############ descr="This is description of " @@ -284,19 +294,19 @@ descr=descr + " and " +self._name #################### return descr - + def get_family(self): # fake data ############### - return "Family of "+ self._name - + return "Family of "+ self._name + def get_properties(self): properties = [] # fake data ###################### properties.append(PropertyInfo("my parameter", "string", "0D", "deviceName")) properties.append(PropertyInfo("asdsadasd", "integer", "0D", 5)) properties.append(PropertyInfo("boollll0", "boolean", "0D", False)) - properties.append(PropertyInfo("boollll0", "boolean", "0D", True)) - properties.append(PropertyInfo("boollll0", "boolean", "0D", False)) + properties.append(PropertyInfo("boollll0", "boolean", "0D", True)) + properties.append(PropertyInfo("boollll0", "boolean", "0D", False)) properties.append(PropertyInfo("number1", "float", "0D", 3.5)) properties.append(PropertyInfo("string2", "string", "0D", "hehe")) properties.append(PropertyInfo("tableIntegerD1", "integer", "1D", [1,2,3])) @@ -308,9 +318,9 @@ properties.append(PropertyInfo("tableinteger2", "integer", "2D",[ [1,2,3],[11,22,33],[-10,-20,-30] ])) properties.append(PropertyInfo("tablefloatD2", "float", "2D",[ [0.5,0.6,0.8],[0.4,0.0,0.333333],[-0.1111,1,123123.6] ])) properties.append(PropertyInfo("tablestringD2", "string", "2D",[ ["aaaa","bbb","ccc"],["aaaa2","bbb2","ccc2"],["aaaa3","bbb3","ccc3"] ])) - + return properties - + def get_controller_type(self): return self._type @@ -321,7 +331,7 @@ # THIS IS USED FOR TEST PURPOSES ONLY. DO NOT USE IT OUTSIDE SARDANA TESTS #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class ControllerInfo(object): - + def __init__(self, name, ctrl_class_info): self._name = name self._ctrl_class_info = ctrl_class_info @@ -331,13 +341,13 @@ def get_controller_type(self): return self._ctrl_class_info.get_controller_type() - + def get_name(self): return self._name - + def get_max_elements(self): return self._ctrl_class_info.get_max_elements() - + def is_axis_free(self, axis): #fake data if axis == 3: @@ -354,8 +364,6 @@ def get_icon(self): return self._ctrl_class_info.get_icon() - - return properties #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # T E M P O R A R Y I M P L E M E N T A T I O N @@ -363,7 +371,7 @@ # THIS IS USED FOR TEST PURPOSES ONLY. DO NOT USE IT OUTSIDE SARDANA TESTS #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class Pool(object): - + def __init__(self, sardana, name, poolpath, version, alias=None, device_name=None): self._sardana = sardana self._name = name @@ -371,16 +379,16 @@ self._version = version self._alias = alias self._device_name = device_name - + def starter_run(self, host, level=1): return True - + def get_name(self): return self._name - + def local_run(self): return True - + def get_element_types(self): return sorted(PoolElementType.keys()) @@ -391,7 +399,7 @@ data.append(ControllerClassInfo("motorController"+str(i), PoolElementType.Motor, None)) for i in range(5): data.append(ControllerClassInfo("counterTimerController"+str(i), PoolElementType.CounterTimer, None)) - + return data def get_controller_infos(self): @@ -402,10 +410,10 @@ for i in range(2): data.append(ControllerInfo("My_ct_ctrl_"+str(i), ctrl_classes[i+5])) return data - + def create_controller(self,controller_class_info, name, properties ): pass - + def create_element(self, controller_name, name, axis): pass @@ -416,7 +424,7 @@ # THIS IS USED FOR TEST PURPOSES ONLY. DO NOT USE IT OUTSIDE SARDANA TESTS #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class MacroServer(object): - + def __init__(self, sardana, name, macropath, pool_names, version, alias=None, device_name=None): self._sardana = sardana self._name = name @@ -426,7 +434,7 @@ self._alias = alias self._device_name = device_name self._doors = [] - + def create_door(self, alias, device_name): try: return self._create_door(alias, device_name) @@ -434,7 +442,7 @@ db = self.get_database() db.delete_device(device_name) raise - + def _create_door(self, alias, device_name): db = self.get_database() info = PyTango.DbDevInfo() @@ -447,16 +455,16 @@ door = Door(alias=alias, device_name=device_name) self._doors.append(door) return door - + def remove_door(self, device_name): pass - + def starter_run(self, host, level=1): return True - + def local_run(self): return True - + def get_database(self): return self._sardana.get_database() @@ -466,7 +474,7 @@ # THIS IS USED FOR TEST PURPOSES ONLY. DO NOT USE IT OUTSIDE SARDANA TESTS #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class Door(object): - + def __init__(self, alias=None, device_name=None): self._name = alias self._device_name = device_name @@ -478,7 +486,7 @@ # THIS IS USED FOR TEST PURPOSES ONLY. DO NOT USE IT OUTSIDE SARDANA TESTS #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class Sardana(object): - + def __init__(self, sardana_db , name, device_name=None): self._sardana_db = sardana_db self._name = name @@ -486,7 +494,7 @@ self._pools = [] self._macroservers = [] self._init() - + def _init(self): if not self._device_name: return @@ -516,23 +524,23 @@ pool_alias = pool_dev_info.alias() pool = Pool(self, pool_name, pool_props.get("poolpath"), pool_props.get("version"), pool_alias, pool_dev_name) self._pools.append(pool) - + def get_name(self): return self._name - + def set_device_name(self, device_name): self._device_name = device_name self._init() - + def get_device_name(self): return self._device_name - + def get_pools(self): return self._pools - + def get_macro_servers(self): return self._macro_servers - + def create_pool(self, name, poolpath, version, alias=None, device_name=None): try: return self._create_pool(name, poolpath, version, alias=alias, device_name=device_name) @@ -540,7 +548,7 @@ db = self.get_database() db.delete_device(device_name) raise - + def _create_pool(self, name, poolpath, version, alias=None, device_name=None): db = self.get_database() info = PyTango.DbDevInfo() @@ -550,13 +558,13 @@ db.add_device(info) if alias: db.put_device_alias(device_name, alias) - + db.put_device_property(device_name,{"PoolPath" : poolpath, "Version": version} ) pool = Pool(self, name, poolpath, version, alias=alias, device_name=device_name) self._pools.append(pool) db.cache().refresh() return pool - + def create_macroserver(self, name, macropath, pool_names, version, alias=None, device_name=None): try: return self._create_macroserver(name, macropath, pool_names, version, alias=alias, device_name=device_name) @@ -564,7 +572,7 @@ db = self.get_database() db.delete_device(device_name) raise - + def _create_macroserver(self, name, macropath, pool_names, version, alias=None, device_name=None): db = self.get_database() info = PyTango.DbDevInfo() @@ -574,16 +582,16 @@ db.add_device(info) if alias: db.put_device_alias(device_name, alias) - + db.put_device_property(device_name,{"MacroPath" : macropath, "Version": version, "PoolNames":pool_names} ) ms = MacroServer(self, name, macropath, pool_names, version, alias=alias, device_name=device_name) self._macroservers.append(ms) db.cache().refresh() return ms - + def remove_pool(self): pass - + def remove_macroserver(self): pass @@ -597,12 +605,12 @@ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class DatabaseSardana(object): """A class containning all sardanas for a single database""" - + def __init__(self, db): assert(db is not None) self._db = db self.refresh() - + def refresh(self): self._sardanas = sardanas = {} services = self._db.get_service_list("Sardana/.*") @@ -612,7 +620,7 @@ sardanas[service_instance] = Sardana(self, service_instance, dev) except: pass - + def create_sardana(self, name, device_name): if self._sardanas.has_key(name): raise Exception("Sardana '%s' already exists" % name) @@ -620,20 +628,20 @@ sardana = Sardana(self, name) self._sardanas[name] = sardana return sardana - + def remove_sardana(self, name): try: - sardana = self._sardanas.pop(name) + self._sardanas.pop(name) except KeyError: raise Exception("Sardana '%s' does NOT exist" % name) self._db.unregister_service("Sardana", name) def get_sardanas(self): return self._sardanas - + def get_sardana(self, name): return self._sardanas[name] - + def get_database(self): return self._db @@ -643,7 +651,7 @@ # THIS IS USED FOR TEST PURPOSES ONLY. DO NOT USE IT OUTSIDE SARDANA TESTS #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- class SardanaManager(Singleton, Logger): - + def __init__(self): """ Initialization. Nothing to be done here for now.""" pass @@ -654,9 +662,10 @@ name = self.__class__.__name__ self.call__init__(Logger, name) self._db_sardanas = {} - + def _get_db_sardana(self, db=None): if db is None: + import taurus db = taurus.Database() db_sardana = self._db_sardanas.get(db) if db_sardana is None: @@ -668,36 +677,37 @@ def remove_sardana(self, name, db=None): self._get_db_sardana(db).remove_sardana(name) - + def get_sardanas(self, db=None): return self._get_db_sardana(db).get_sardanas() - + def get_sardana(self, name, db=None): return self._get_db_sardana(db).get_sardana(name) - + def get_hosts(self): return ["localhost"] + ["controls%02d" % i for i in range(5)] - + def get_level_range(self): return 1, 200 - + def has_localhost_starter(self): + import socket return socket.gethostname() in self.get_hosts() - + @classmethod def get_default_pool_path(cls): pathList = [] pathList.append("/homelocal/sicilia/lib/poolcontrollers") pathList.append("/homelocal/sicilia/lib/python/site-packages/poolcontrollers") return pathList - + @classmethod def get_default_ms_path(cls): pathList = [] pathList.append("/homelocal/sicilia/lib/python/site-packages/macroserver/macros") return pathList - - - - - \ No newline at end of file + + + + + diff -Nru taurus-3.0.0/lib/taurus/core/tango/search.py taurus-3.1.0/lib/taurus/core/tango/search.py --- taurus-3.0.0/lib/taurus/core/tango/search.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/search.py 2013-07-25 07:53:42.000000000 +0000 @@ -0,0 +1,123 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +""" +search.py: methods for getting matching device/attribute/alias names from Tango database + +These methods have been borrowed from fandango modules. +""" + +import re +import taurus + +############################################################################### +# Utils + +def searchCl(regexp,target): + return re.search(regexp.lower(),target.lower()) + +def matchCl(regexp,target): + return re.match(regexp.lower(),target.lower()) + +def is_regexp(s): + return any(c in s for c in '.*[]()+?') + +def extend_regexp(s): + s = str(s).strip() + if '.*' not in s: + s = s.replace('*','.*') + if '.*' not in s: + if ' ' in s: s = s.replace(' ','.*') + if '/' not in s: s = '.*'+s+'.*' + else: + if not s.startswith('^'): s = '^'+s + if not s.endswith('$'): s = s+'$' + return s + +def isString(s): + typ = s.__class__.__name__.lower() + return not hasattr(s,'__iter__') and 'str' in typ and 'list' not in typ + +def isCallable(obj): + return hasattr(obj,'__call__') + +def isMap(obj): + return hasattr(obj,'has_key') or hasattr(obj,'items') + +def isDictionary(obj): + return isMap(obj) + +def isSequence(obj): + typ = obj.__class__.__name__.lower() + return (hasattr(obj,'__iter__') or 'list' in typ) and not isString(obj) and not isMap(obj) + +def split_model_list(modelNames): + '''convert str to list if needed (commas and whitespace are considered as separators)''' + if isString(modelNames): #isinstance(modelNames,(basestring,Qt.QString)): + modelNames = str(modelNames).replace(',',' ') + modelNames = modelNames.split() + if isSequence(modelNames): #isinstance(modelNames,(list.Qt.QStringList)): + modelNames = [str(s) for s in modelNames] + return modelNames + +def get_matching_devices(expressions,limit=0,exported=False): + """ + Searches for devices matching expressions, if exported is True only running devices are returned + """ + db = taurus.Database() + all_devs = [s.lower() for s in db.get_device_name('*','*')] + #This code is used to get data from multiples hosts + #if any(not fun.matchCl(rehost,expr) for expr in expressions): all_devs.extend(get_all_devices(exported)) + #for expr in expressions: + #m = fun.matchCl(rehost,expr) + #if m: + #host = m.groups()[0] + #print 'get_matching_devices(%s): getting %s devices ...'%(expr,host) + #odb = PyTango.Database(*host.split(':')) + #all_devs.extend('%s/%s'%(host,d) for d in odb.get_device_name('*','*')) + result = [e for e in expressions if e.lower() in all_devs] + expressions = [extend_regexp(e) for e in expressions if e not in result] + result.extend(filter(lambda d: any(matchCl(extend_regexp(e),d) for e in expressions),all_devs)) + return result + +def get_device_for_alias(alias): + db = taurus.Database() + try: return db.get_device_alias(alias) + except Exception,e: + if 'no device found' in str(e).lower(): return None + return None #raise e + +def get_alias_for_device(dev): + db = taurus.Database() + try: + result = db.get_alias(dev) #.get_database_device().DbGetDeviceAlias(dev) + return result + except Exception,e: + if 'no alias found' in str(e).lower(): return None + return None #raise e + +def get_alias_dict(exp='*'): + tango = taurus.Database() + return dict((k,tango.get_device_alias(k)) for k in tango.get_device_alias_list(exp)) \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/core/tango/tangoattribute.py taurus-3.1.0/lib/taurus/core/tango/tangoattribute.py --- taurus-3.0.0/lib/taurus/core/tango/tangoattribute.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/tangoattribute.py 2013-07-25 07:53:42.000000000 +0000 @@ -31,19 +31,20 @@ # -*- coding: utf-8 -*- import time -import numpy import threading import PyTango -import taurus.core -from taurus.core import TaurusEventType, TaurusSerializationMode, \ +from taurus import Factory, Manager +from taurus.core.taurusattribute import TaurusAttribute, TaurusStateAttribute +from taurus.core.taurusbasetypes import TaurusEventType, TaurusSerializationMode, \ SubscriptionState -from taurus.core.util import EventListener -from enums import EVENT_TO_POLLING_EXCEPTIONS +from taurus.core.taurusoperation import WriteAttrOperation +from taurus.core.util.event import EventListener +from .enums import EVENT_TO_POLLING_EXCEPTIONS DataType = PyTango.CmdArgType -class TangoAttribute(taurus.core.TaurusAttribute): +class TangoAttribute(TaurusAttribute): # helper class property that stores a reference to the corresponding factory _factory = None @@ -69,7 +70,7 @@ self.__subscription_state = SubscriptionState.Unsubscribed self.__subscription_event = threading.Event() - self.call__init__(taurus.core.TaurusAttribute, name, parent, **kwargs) + self.call__init__(TaurusAttribute, name, parent, **kwargs) def __getattr__(self,name): return getattr(self._getRealConfig(), name) @@ -89,7 +90,7 @@ @classmethod def factory(cls): if cls._factory is None: - cls._factory = taurus.Factory(scheme='tango') + cls._factory = Factory(scheme='tango') return cls._factory def getNewOperation(self, value): @@ -181,7 +182,8 @@ if PyTango.is_float_type(type): attrvalue = float(value) elif PyTango.is_int_type(type): - attrvalue = int(value) + #attrvalue = int(value) + attrvalue = long(value) #changed as a partial workaround to a problem in PyTango writing to DevULong64 attributes (see ALBA RT#29793) elif type == DataType.DevBoolean: try: attrvalue = bool(int(value)) @@ -209,7 +211,7 @@ try: dev = self.getParentObj() name, value = self.getSimpleName(), self.encode(value) - if self.isUsingEvents(): + if self.isUsingEvents() or not self.isReadWrite(): with_read = False if with_read: try: @@ -332,7 +334,7 @@ listeners = self._listeners initial_subscription_state = self.__subscription_state - ret = taurus.core.TaurusAttribute.addListener(self, listener) + ret = TaurusAttribute.addListener(self, listener) if not ret: return ret @@ -345,7 +347,7 @@ if len(listeners) > 1 and (initial_subscription_state == SubscriptionState.Subscribed or self.isPollingActive()): sm = self.getSerializationMode() if sm == TaurusSerializationMode.Concurrent: - taurus.Manager().addJob(self.__fireRegisterEvent, None, (listener,)) + Manager().addJob(self.__fireRegisterEvent, None, (listener,)) else: self.__fireRegisterEvent((listener,)) return ret @@ -354,7 +356,7 @@ """ Remove a TaurusListener from the listeners list. If polling enabled and it is the last element the stop the polling timer. If the listener is not registered nothing happens.""" - ret = taurus.core.TaurusAttribute.removeListener(self, listener) + ret = TaurusAttribute.removeListener(self, listener) cfg = self._getRealConfig() cfg.removeListener(listener) @@ -446,7 +448,7 @@ Default implementation propagates the event to all listeners.""" curr_time = time.time() - manager = taurus.Manager() + manager = Manager() sm = self.getSerializationMode() if not event.err: self.__attr_value, self.__attr_err, self.__attr_timestamp = self.decode(event.attr_value), None, curr_time @@ -483,10 +485,10 @@ return False -class TangoStateAttribute(TangoAttribute, taurus.core.TaurusStateAttribute): +class TangoStateAttribute(TangoAttribute, TaurusStateAttribute): def __init__(self, name, parent, **kwargs): self.call__init__(TangoAttribute, name, parent, **kwargs) - self.call__init__(taurus.core.TaurusStateAttribute, name, parent, **kwargs) + self.call__init__(TaurusStateAttribute, name, parent, **kwargs) class TangoAttributeEventListener(EventListener): @@ -505,3 +507,16 @@ if t not in (TaurusEventType.Change, TaurusEventType.Periodic): return self.fireEvent(v.value) + + + +def test1(): + import numpy + from taurus import Attribute + a = Attribute('sys/tg_test/1/ulong64_scalar') + + a.write(numpy.uint64(88)) + +if __name__ == "__main__": + test1() + diff -Nru taurus-3.0.0/lib/taurus/core/tango/tangoconfiguration.py taurus-3.1.0/lib/taurus/core/tango/tangoconfiguration.py --- taurus-3.0.0/lib/taurus/core/tango/tangoconfiguration.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/tangoconfiguration.py 2013-07-25 07:53:42.000000000 +0000 @@ -30,20 +30,22 @@ __docformat__ = "restructuredtext" # -*- coding: utf-8 -*- -import taurus.core import threading import weakref import time import PyTango -from enums import EVENT_TO_POLLING_EXCEPTIONS +from taurus import Factory, Manager +from taurus.core.taurusbasetypes import TaurusEventType +from taurus.core.taurusconfiguration import TaurusConfiguration +from .enums import EVENT_TO_POLLING_EXCEPTIONS -class TangoConfiguration(taurus.core.TaurusConfiguration): +class TangoConfiguration(TaurusConfiguration): def __init__(self, name, parent, storeCallback = None): self._events_working = False - self.call__init__(taurus.core.TaurusConfiguration, name, parent, storeCallback) + self.call__init__(TaurusConfiguration, name, parent, storeCallback) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusModel necessary overwrite @@ -55,7 +57,7 @@ @classmethod def factory(cls): if cls._factory is None: - cls._factory = taurus.Factory("tango") + cls._factory = Factory("tango") return cls._factory def __getattr__(self, name): @@ -129,18 +131,18 @@ def __fireRegisterEvent(self, listener): value = self.getValueObj() if value is not None: - self.fireEvent(taurus.core.TaurusEventType.Config, value, listener) + self.fireEvent(TaurusEventType.Config, value, listener) def addListener(self, listener): """ Add a TaurusListener object in the listeners list. If the listener is already registered nothing happens.""" - ret = taurus.core.TaurusConfiguration.addListener(self, listener) + ret = TaurusConfiguration.addListener(self, listener) if not ret: return ret #fire a first configuration event #if len(self._listeners) > 1 or not self._events_working: - taurus.Manager().addJob(self.__fireRegisterEvent, None, (listener,)) + Manager().addJob(self.__fireRegisterEvent, None, (listener,)) return ret #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- @@ -234,12 +236,12 @@ self._attr_timestamp = time.time() self._attr_info = self.decode(event.attr_conf) listeners = tuple(self._listeners) - #taurus.Manager().addJob(self._push_event, None, event) - taurus.Manager().addJob(self.fireEvent, None, taurus.core.TaurusEventType.Config, self._attr_info, listeners=listeners) + #Manager().addJob(self._push_event, None, event) + Manager().addJob(self.fireEvent, None, TaurusEventType.Config, self._attr_info, listeners=listeners) #def _push_event(self, event): # """ Notify listeners when event received""" - # self.fireEvent(taurus.core.TaurusEventType.Config, self._attr_info) + # self.fireEvent(TaurusEventType.Config, self._attr_info) #=========================================================================== # Some methods reimplemented from TaurusConfiguration @@ -336,7 +338,7 @@ def setDescription(self,descr): config = self.getValueObj() if config: - config.description = description + config.description = descr self._applyConfig() def setLabel(self,lbl): diff -Nru taurus-3.0.0/lib/taurus/core/tango/tangodatabase.py taurus-3.1.0/lib/taurus/core/tango/tangodatabase.py --- taurus-3.0.0/lib/taurus/core/tango/tangodatabase.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/tangodatabase.py 2013-07-25 07:53:42.000000000 +0000 @@ -34,13 +34,19 @@ import PyTango import PyTango.utils -import taurus.core -import taurus.core.util + +from taurus import Factory +from taurus.core.taurusbasetypes import TaurusSWDevHealth +from taurus.core.taurusdatabase import TaurusDatabaseCache, TaurusDevInfo, \ + TaurusAttrInfo, TaurusServInfo, TaurusDevClassInfo, TaurusDevTree, \ + TaurusServerTree +from taurus.core.util.containers import CaselessDict +from taurus.core.taurusdatabase import TaurusDatabase InvalidAlias = "nada" -class TangoDevInfo(taurus.core.TaurusDevInfo): +class TangoDevInfo(TaurusDevInfo): def __init__(self, container, name=None, full_name=None, alias=None, server=None, klass=None, exported=False, host=None): super(TangoDevInfo, self).__init__(container, name=name, full_name=full_name, alias=alias, server=server, klass=klass, exported=exported, host=host) @@ -84,30 +90,32 @@ return self._health exported = self.exported() if exported: - self._health = taurus.core.TaurusSWDevHealth.Exported + self._health = TaurusSWDevHealth.Exported else: - self._health = taurus.core.TaurusSWDevHealth.NotExported + self._health = TaurusSWDevHealth.NotExported return self._health def refreshAttributes(self): attrs = [] try: dev = self.getHWObj() + if dev is None: + raise PyTango.DevFailed() # @todo: check if this is the right exception to throw attr_info_list = dev.attribute_list_query_ex() for attr_info in attr_info_list: full_name = "%s/%s" % (self.fullName(), attr_info.name) - attr_obj = taurus.core.TaurusAttrInfo(self.container(), + attr_obj = TaurusAttrInfo(self.container(), name=attr_info.name.lower(), full_name=full_name.lower(), device=self, info=attr_info) attrs.append(attr_obj) attrs = sorted(attrs, key=lambda attr : attr.name()) - except PyTango.DevFailed, df: - if self.health() == taurus.core.TaurusSWDevHealth.Exported: - self._health = taurus.core.TaurusSWDevHealth.ExportedNotAlive + except PyTango.DevFailed as df: + if self.health() == TaurusSWDevHealth.Exported: + self._health = TaurusSWDevHealth.ExportedNotAlive self.setAttributes(attrs) -class TangoServInfo(taurus.core.TaurusServInfo): +class TangoServInfo(TaurusServInfo): def __init__(self, container, name=None, full_name=None): super(TangoServInfo, self).__init__(container, name=name, full_name=full_name) @@ -132,7 +140,7 @@ return self._alive -class TangoDatabaseCache(taurus.core.TaurusDatabaseCache): +class TangoDatabaseCache(TaurusDatabaseCache): def refresh(self): db = self.db @@ -144,7 +152,7 @@ results, data = r[0][:-2], r[1] assert row_nb == len(data) / column_nb - CD = taurus.core.util.CaselessDict + CD = CaselessDict #CD = dict dev_dict, serv_dict, klass_dict, alias_dict = CD(), {}, {}, CD() @@ -155,13 +163,13 @@ if not len(alias): alias = None serv_dict[server] = si = serv_dict.get(server, - TangoServInfo(self, name=server, + TangoServInfo(self, name=server, full_name=server)) klass_dict[klass] = dc = klass_dict.get(klass, - taurus.core.TaurusDevClassInfo(self, - name=klass, - full_name=klass)) + TaurusDevClassInfo(self, + name=klass, + full_name=klass)) full_name = "tango://%s/%s" % (db.getFullName(), name) dev_dict[name] = di = TangoDevInfo(self, name=name, full_name=full_name, @@ -174,8 +182,8 @@ alias_dict[alias] = di self._devices = dev_dict - self._device_tree = taurus.core.TaurusDevTree(dev_dict) - self._server_tree = taurus.core.TaurusServerTree(serv_dict) + self._device_tree = TaurusDevTree(dev_dict) + self._server_tree = TaurusServerTree(serv_dict) self._servers = serv_dict self._klasses = klass_dict self._aliases = alias_dict @@ -194,13 +202,12 @@ attr_info_list = dev.attribute_list_query_ex() for attr_info in attr_info_list: full_attr_name = "%s/%s" % (full_name, attr_info.name) - attr_obj = taurus.core.TaurusAttrInfo(self, name=attr_info.name, - full_name=full_attr_name, - device=device, - info=attr_info) + attr_obj = TaurusAttrInfo(self, name=attr_info.name, + full_name=full_attr_name, + device=device, info=attr_info) attrs.append(attr_obj) attrs = sorted(attrs, key=lambda attr : attr.name().lower()) - except PyTango.DevFailed, df: + except PyTango.DevFailed as df: pass device.setAttributes(attrs) @@ -276,23 +283,24 @@ return val -class TangoDatabase(taurus.core.TaurusDatabase): +class TangoDatabase(TaurusDatabase): def __init__(self,host=None,port=None,parent=None): - - pars = host, port + pars = () if host is None or port is None: try: - pars = TangoDatabase.get_default_tango_host().split(':') + host, port = TangoDatabase.get_default_tango_host().rsplit(':', 1) + pars = host, port except Exception, e: - pars = () print "Error getting env TANGO_HOST:", str(e) + else: + pars = host, port self.dbObj = PyTango.Database(*pars) self._dbProxy = None self._dbCache = None - complete_name = "%s:%s" % (self.dbObj.get_db_host(), self.dbObj.get_db_port()) - self.call__init__(taurus.core.TaurusDatabase, complete_name, parent) + complete_name = "%s:%s" % (host, port) + self.call__init__(TaurusDatabase, complete_name, parent) try: self.get_class_for_device(self.dev_name()) @@ -340,7 +348,7 @@ @classmethod def factory(cls): if cls._factory is None: - cls._factory = taurus.Factory(scheme='tango') + cls._factory = Factory(scheme='tango') return cls._factory def getValueObj(self,cache=True): diff -Nru taurus-3.0.0/lib/taurus/core/tango/tangodevice.py taurus-3.1.0/lib/taurus/core/tango/tangodevice.py --- taurus-3.0.0/lib/taurus/core/tango/tangodevice.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/tangodevice.py 2013-07-25 07:53:42.000000000 +0000 @@ -32,16 +32,25 @@ import time import PyTango -import taurus.core -from taurus.core import TaurusSWDevState, TaurusLockInfo, LockStatus +from taurus import Factory +from taurus.core.taurusdevice import TaurusDevice +from taurus.core.taurusbasetypes import TaurusSWDevState, TaurusLockInfo, LockStatus DFT_TANGO_DEVICE_DESCRIPTION = "A TANGO device" +class _TangoInfo(object): + + def __init__(self): + self.dev_class = self.dev_type = 'TangoDevice' + self.doc_url = 'http://www.esrf.fr/computing/cs/tango/tango_doc/ds_doc/' + self.server_host = 'Unknown' + self.server_id = 'Unknown' + self.server_version = 1 -class TangoDevice(taurus.core.TaurusDevice): +class TangoDevice(TaurusDevice): def __init__(self, name, **kw): """Object initialization.""" - self.call__init__(taurus.core.TaurusDevice, name, **kw) + self.call__init__(TaurusDevice, name, **kw) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusModel necessary overwrite @@ -52,7 +61,7 @@ @classmethod def factory(cls): if cls._factory is None: - cls._factory = taurus.Factory(scheme='tango') + cls._factory = Factory(scheme='tango') return cls._factory #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- @@ -72,7 +81,7 @@ def lock(self, force=False): li = self.getLockInfo() if force: - if self.getLockInfo().status == LockInfo.Locked: + if self.getLockInfo().status == TaurusLockInfo.Locked: self.unlock(force=True) return self.getHWObj().lock() @@ -202,4 +211,22 @@ v, err = da, None attr = attrs[da.name] attr.poll(single=False, value=v, error=err, time=t) - + + def _repr_html_(self): + try: + info = self.getHWObj().info() + except: + info = _TangoInfo() + txt = """\ + + + + + + + +
Short name{simple_name}
Standard name{normal_name}
Full name{full_name}
Device class{dev_class}
Server{server_id}
Documentation{doc_url}
+""".format(simple_name=self.getSimpleName(), normal_name=self.getNormalName(), + full_name=self.getFullName(), dev_class=info.dev_class, + server_id=info.server_id, doc_url=info.doc_url) + return txt diff -Nru taurus-3.0.0/lib/taurus/core/tango/tangofactory.py taurus-3.1.0/lib/taurus/core/tango/tangofactory.py --- taurus-3.0.0/lib/taurus/core/tango/tangofactory.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tango/tangofactory.py 2013-07-25 07:53:42.000000000 +0000 @@ -34,24 +34,28 @@ import threading import PyTango -import taurus.core -import taurus.core.util -from taurus.core import OperationMode, MatchLevel, TaurusException - -import tangodatabase -import tangoattribute -import tangodevice -import tangoconfiguration - -_Database = tangodatabase.TangoDatabase -_Attribute = tangoattribute.TangoAttribute -_StateAttribute = tangoattribute.TangoStateAttribute -_Device = tangodevice.TangoDevice -_Configuration = tangoconfiguration.TangoConfiguration +from taurus.core.taurusfactory import TaurusFactory +from taurus.core.taurusbasetypes import OperationMode, MatchLevel +from taurus.core.taurusexception import TaurusException, DoubleRegistration +from taurus.core.tauruspollingtimer import TaurusPollingTimer +from taurus.core.util.enumeration import Enumeration +from taurus.core.util.log import Logger +from taurus.core.util.singleton import Singleton +from taurus.core.util.containers import CaselessWeakValueDict, CaselessDict + +from .tangodatabase import TangoDatabase, InvalidAlias +from .tangoattribute import TangoAttribute, TangoStateAttribute +from .tangodevice import TangoDevice +from .tangoconfiguration import TangoConfiguration + +_Database = TangoDatabase +_Attribute = TangoAttribute +_StateAttribute = TangoStateAttribute +_Device = TangoDevice +_Configuration = TangoConfiguration -from taurus.core import DoubleRegistration -class TangoFactory(taurus.core.util.Singleton, taurus.core.TaurusFactory, taurus.core.util.Logger): +class TangoFactory(Singleton, TaurusFactory, Logger): """A Singleton class designed to provide Tango related objects. The TangoFactory model containning the Factory for the Tango scheme @@ -94,8 +98,8 @@ """Singleton instance initialization. **For internal usage only**""" name = self.__class__.__name__ - self.call__init__(taurus.core.util.Logger, name) - self.call__init__(taurus.core.TaurusFactory) + self.call__init__(Logger, name) + self.call__init__(TaurusFactory) self._polling_enabled = True self.reInit() @@ -104,20 +108,20 @@ self._default_tango_host = None self.operation_mode = OperationMode.ONLINE self.dft_db = None - self.tango_db = taurus.core.util.CaselessWeakValueDict() - self.tango_db_queries = taurus.core.util.CaselessWeakValueDict() - self.tango_configs = taurus.core.util.CaselessWeakValueDict() - self.tango_attrs = taurus.core.util.CaselessWeakValueDict() - self.tango_devs = taurus.core.util.CaselessWeakValueDict() - self.tango_dev_queries = taurus.core.util.CaselessWeakValueDict() - self.tango_alias_devs = taurus.core.util.CaselessWeakValueDict() + self.tango_db = CaselessWeakValueDict() + self.tango_db_queries = CaselessWeakValueDict() + self.tango_configs = 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 = taurus.core.util.CaselessDict() + self.tango_attr_klasses = CaselessDict() self.tango_attr_klasses["state"] = _StateAttribute def cleanUp(self): @@ -212,8 +216,8 @@ :param absolute_name: (str) the object absolute name string - :return: (taurus.core.TaurusModel) a class object that should be a subclass of a taurus.core.TaurusModel - :raise: (taurus.core.TaurusException) if the given name is invalid. + :return: (taurus.core.taurusmodel.TaurusModel) a class object that should be a subclass of a taurus.core.taurusmodel.TaurusModel + :raise: (taurus.core.taurusexception.TaurusException) if the given name is invalid. """ objType = None try: @@ -247,8 +251,8 @@ :param db_name: (str) database name string alias. If None, the default database is used - :return: (taurus.core.TangoDatabase) database object - :raise: (taurus.core.TaurusException) if the given alias is invalid. + :return: (taurus.core.tangodatabase.TangoDatabase) database object + :raise: (taurus.core.taurusexception.TaurusException) if the given alias is invalid. """ ret = None if db_name is None: @@ -300,7 +304,7 @@ (_/_/_) or a device alias. :return: (taurus.core.tango.TangoDevice) a device object - :raise: (taurus.core.TaurusException) if the given dev_name is invalid. + :raise: (taurus.core.taurusexception.TaurusException) if the given dev_name is invalid. """ d = self.tango_devs.get(dev_name) if d is None: @@ -333,7 +337,7 @@ if dev_name: try: alias = db.get_alias(dev_name) - if alias and alias.lower() == taurus.core.InvalidAlias: + if alias and alias.lower() == InvalidAlias: alias = None except: alias = None @@ -371,8 +375,8 @@ :param attr_name: (str) attribute name - :return: (taurus.core.TangoAttribute) attribute object - :raise: (taurus.core.TaurusException) if the given alias is invalid. + :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) @@ -455,7 +459,7 @@ If the corresponding configuration already exists, the existing instance is returned. Otherwise a new instance is stored and returned. - :param param: (taurus.core.TaurusAttribute or str) attrubute object or full configuration name + :param param: (taurus.core.taurusattribute.TaurusAttribute or str) attrubute object or full configuration name :return: (taurus.core.tango.TangoConfiguration) configuration object """ @@ -490,7 +494,7 @@ params = validator.getParams(cfg_name) if params is None: - raise taurus.core.TaurusException("Invalid Tango configuration name %s" % cfg_name) + raise TaurusException("Invalid Tango configuration name %s" % cfg_name) host,port = params.get('host'),params.get('port') db = None @@ -639,7 +643,7 @@ if dev_name: try: alias = db.get_alias(dev_name) - if alias and alias.lower() == taurus.core.InvalidAlias: + if alias and alias.lower() == InvalidAlias: alias = None except: alias = None @@ -698,7 +702,7 @@ :param period: (float) polling period (in seconds) :param unsubscribe_evts: (bool) wheater or not to unsubscribe from events """ - tmr = self.polling_timers.get(period,taurus.core.TaurusPollingTimer(period)) + tmr = self.polling_timers.get(period, TaurusPollingTimer(period)) self.polling_timers[period] = tmr tmr.addAttribute(attribute, self.isPollingEnabled()) diff -Nru taurus-3.0.0/lib/taurus/core/taurusattribute.py taurus-3.1.0/lib/taurus/core/taurusattribute.py --- taurus-3.0.0/lib/taurus/core/taurusattribute.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusattribute.py 2013-07-25 07:53:43.000000000 +0000 @@ -31,14 +31,14 @@ import weakref -import taurusmodel -import taurusconfiguration -from enums import TaurusEventType +from taurus.core.taurusbasetypes import TaurusElementType +from .taurusmodel import TaurusModel +from .taurusconfiguration import TaurusConfigurationProxy -class TaurusAttribute(taurusmodel.TaurusModel): +class TaurusAttribute(TaurusModel): def __init__(self, name, parent, **kwargs): - self.call__init__(taurusmodel.TaurusModel, name, parent) + self.call__init__(TaurusModel, name, parent) self.__parentDevice = parent # just to keep it alive @@ -65,22 +65,18 @@ self._dev_hw_obj = parent.getHWObj() - def __str__(self): - return self.getFullName() - def cleanUp(self): self.trace("[TaurusAttribute] cleanUp") self._unsubscribeEvents() self._dev_hw_obj = None - taurusmodel.TaurusModel.cleanUp(self) + TaurusModel.cleanUp(self) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusModel implementation #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def getTaurusElementType(self): - import taurus.core - return taurus.core.TaurusElementType.Attribute + return TaurusElementType.Attribute @classmethod def buildModelName(cls, parent_model, relative_name): @@ -159,7 +155,7 @@ def getValueObj(self, cache=True): try: return self.read(cache=cache) - except Exception, e: + except Exception: return None def getDisplayDescrObj(self,cache=True): @@ -226,10 +222,9 @@ ret = None try: if self.isScalar(): - format = self.getFormat() - if self.isNumeric() and format is not None: - format = self.getFormat() - ret = self.getFormat() % value + fmt = self.getFormat() + if self.isNumeric() and fmt is not None: + ret = fmt % value else: ret = str(value) elif self.isSpectrum(): @@ -315,9 +310,10 @@ :param period: polling period (in miliseconds) :type period: int """ - self.deprecated("use changePollingPeriod(). Not exactly the same functionality. Only activates polling if necessary") - self.changePollingPeriod(period, force=force) - self.enablePolling() + ## REENABLED, used to solve problems with ID GUI's and other systems where event independency is needed. + #self.deprecated("use changePollingPeriod(). Not exactly the same functionality. Only activates polling if necessary") + self.changePollingPeriod(period) + self.enablePolling(force=force) def deactivatePolling(self, maintain_enabled=False): """unregister attribute from polling""" @@ -343,7 +339,7 @@ if ob is not None: return ob - ob = taurusconfiguration.TaurusConfigurationProxy(self) + ob = TaurusConfigurationProxy(self) self.__weakFakeConfigObj = weakref.ref(ob) return ob @@ -372,4 +368,6 @@ def isInformDeviceOfErrors(self): return True - +#del weakef +#del TaurusModel +#del TaurusConfigurationProxy diff -Nru taurus-3.0.0/lib/taurus/core/taurusbasetypes.py taurus-3.1.0/lib/taurus/core/taurusbasetypes.py --- taurus-3.0.0/lib/taurus/core/taurusbasetypes.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusbasetypes.py 2013-07-25 07:53:43.000000000 +0000 @@ -26,10 +26,156 @@ a misc collection of basic types ''' +__all__ = ["TaurusSWDevState", "TaurusSWDevHealth", "OperationMode", + "TaurusSerializationMode", "SubscriptionState", "TaurusEventType", + "MatchLevel", "TaurusElementType", "LockStatus", "DataFormat", + "AttrQuality", "AttrAccess", "DisplayLevel", "ManagerState", + "TaurusTimeVal", "TaurusAttrValue", "TaurusConfigValue", + "TaurusLockInfo"] + +__docformat__ = "restructuredtext" + import time import datetime -from enums import AttrQuality, AttrAccess, DataFormat, LockStatus +from .util.enumeration import Enumeration + +TaurusSWDevState = Enumeration( +'TaurusSWDevState', ( + 'Uninitialized', + 'Running', + 'Shutdown', + 'Crash', + 'EventSystemShutdown' +)) + +TaurusSWDevHealth = Enumeration( +'TaurusSWDevHealth', ( + 'Exported', # device reported exported + 'ExportedAlive', # device reported exported and confirmed connection + 'ExportedNotAlive', # device reported exported but connection failed!! + 'NotExported', # device didn't report exported + 'NotExportedAlive', # device didn't report exported but connection confirmed! + 'NotExportedNotAlive' # device didn't report exported and connection failed +)) + +OperationMode = Enumeration( +'OperationMode', ( + 'OFFLINE', + 'ONLINE' +)) + +TaurusSerializationMode = Enumeration( +'TaurusSerializationMode', ( + 'Serial', + 'Concurrent' +)) + +TaurusEventType = Enumeration( +'TaurusEventType', ( + 'Change', + 'Config', + 'Periodic', + 'Error' +)) + +MatchLevel = Enumeration( +'MatchLevel', ( + 'ANY', + 'SHORT', + 'NORMAL', + 'COMPLETE', + 'SHORT_NORMAL', + 'NORMAL_COMPLETE' +)) + +TaurusElementType = Enumeration( +'TaurusElementType', ( + 'Unknown', + 'Name', + 'DeviceClass', + 'Device', + 'DeviceAlias', + 'Domain', + 'Family', + 'Member', + 'Server', + 'ServerName', + 'ServerInstance', + 'Exported', + 'Host', + 'Attribute', + 'AttributeAlias', + 'Command', + 'Property', + 'Configuration', + 'Database', +)) + +LockStatus = Enumeration( +'LockStatus', ( + 'Unlocked', + 'Locked', + 'LockedMaster', + 'Unknown', +)) + +DataFormat = Enumeration( +'DataFormat', ( + '_0D', + '_1D', + '_2D' +)) + +DataType = Enumeration( +'DataType', ( + 'Integer', + 'Float', + 'String', + 'Boolean', +)) + +SubscriptionState = Enumeration( +"SubscriptionState", ( + "Unsubscribed", + "Subscribing", + "Subscribed", + "PendingSubscribe" +)) + +################# +# Not in use yet: + +AttrQuality = Enumeration( +'AttrQuality', ( + 'ATTR_VALID', + 'ATTR_INVALID', + 'ATTR_ALARM' +)) + +AttrAccess = Enumeration( +'AttrAccess', ( + 'READ', + 'READ_WITH_WRITE', + 'WRITE', + 'READ_WRITE' +)) + +DisplayLevel = Enumeration( +'DisplayLevel', ( + 'OPERATOR', + 'EXPERT', + 'DEVELOPER' +)) + +ManagerState = Enumeration( +'ManagerState', ( + 'UNINITIALIZED', + 'INITED', + 'CLEANED' +)) + + class TaurusTimeVal(object): def __init__(self): @@ -147,3 +293,8 @@ def __repr__(self): return self.status_msg + +#del time +#del datetime +#del Enumeration +#del AttrQuality, AttrAccess, DataFormat, LockStatus \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/core/taurusconfiguration.py taurus-3.1.0/lib/taurus/core/taurusconfiguration.py --- taurus-3.0.0/lib/taurus/core/taurusconfiguration.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusconfiguration.py 2013-07-25 07:53:43.000000000 +0000 @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- ############################################################################# ## @@ -29,13 +30,9 @@ __docformat__ = "restructuredtext" -# -*- coding: utf-8 -*- -import time -import weakref -import numpy +from .taurusbasetypes import AttrAccess, TaurusElementType +from .taurusmodel import TaurusModel -from enums import TaurusEventType, AttrAccess -import taurusmodel class TaurusConfigurationProxy(object): """ @@ -54,7 +51,7 @@ return getattr(self.__parent._getRealConfig(), name) -class TaurusConfiguration(taurusmodel.TaurusModel): +class TaurusConfiguration(TaurusModel): no_cfg_value = '-----' no_unit = 'No unit' @@ -83,7 +80,7 @@ # the configuration event identifier self._cfg_evt_id = None - self.call__init__(taurusmodel.TaurusModel, name, parent) + self.call__init__(TaurusModel, name, parent) # Everything went ok so now we are sure we can store the object if not storeCallback is None: @@ -92,6 +89,9 @@ self._dev_hw_obj = self._getDev().getHWObj() self._subscribeEvents() + + def __str__(self): + return self.getFullName() def _subscribeEvents(self): pass @@ -101,15 +101,14 @@ self._unsubscribeEvents() self._attr_info = None self._dev_hw_obj = None - taurusmodel.TaurusModel.cleanUp(self) + TaurusModel.cleanUp(self) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusModel implementation #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def getTaurusElementType(self): - import taurus.core - return taurus.core.TaurusElementType.Configuration + return TaurusElementType.Configuration @classmethod def buildModelName(cls, parent_model, relative_name): @@ -172,7 +171,7 @@ if cache is set to True (default) and the the configuration has events active then it will return the local cached value. Otherwise it will read from the tango layer.""" - raise RuntimeException("May not be called in abstract TaurusConfiguration") + raise RuntimeError("May not be called in abstract TaurusConfiguration") def getDisplayValue(self,cache=True): confvalue = self.getValueObj(cache=cache) @@ -189,8 +188,8 @@ return [('name', self.getLabel(cache=cache))] return attrObj.getDisplayDescrObj(cache=cache) - def isWritable(self): - return True +# def isWritable(self): +# return True #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # API for listeners @@ -199,7 +198,7 @@ # def addListener(self, listener): # """ Add a TaurusListener object in the listeners list. # If the listener is already registered nothing happens.""" -# ret = taurusmodel.TaurusModel.addListener(self, listener) +# ret = TaurusModel.addListener(self, listener) # if not ret: # return ret @@ -393,7 +392,7 @@ def setDescription(self,descr): config = self.getValueObj() if config: - config.description = description + config.description = descr self._applyConfig() def setLabel(self,lbl): @@ -463,8 +462,23 @@ attr = self.getParentObj() if attr is None: return False v = attr.read(cache=cache) + import numpy return numpy.isscalar(v.value) + def isSpectrum(self, cache=True): + attr = self.getParentObj() + if attr is None: return False + v = attr.read(cache=cache) + import numpy + return not numpy.isscalar(v.value) and numpy.array(v.value).ndim == 1 + + def isImage(self, cache=True): + attr = self.getParentObj() + if attr is None: return False + v = attr.read(cache=cache) + import numpy + return not numpy.isscalar(v.value) and numpy.array(v.value).ndim == 2 + def isWrite(self, cache=True): return self.getWritable(cache) == AttrAccess.WRITE @@ -473,3 +487,6 @@ def isReadWrite(self, cache=True): return self.getWritable(cache) == AttrAccess.READ_WRITE + +#del AttrAccess +#del TaurusModel diff -Nru taurus-3.0.0/lib/taurus/core/taurusdatabase.py taurus-3.1.0/lib/taurus/core/taurusdatabase.py --- taurus-3.0.0/lib/taurus/core/taurusdatabase.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusdatabase.py 2013-07-25 07:53:43.000000000 +0000 @@ -34,9 +34,9 @@ import weakref import operator -from enums import TaurusEventType, TaurusSWDevHealth -import taurusmodel -import util +from .taurusbasetypes import TaurusEventType, TaurusSWDevHealth, TaurusElementType +from .taurusmodel import TaurusModel +from .util.containers import CaselessDict DFT_DATABASE_DESCRIPTION = "A database" @@ -131,7 +131,7 @@ 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 = util.CaselessDict() + self._devices = CaselessDict() self._exported = False self._alive = None self._host = "" @@ -187,7 +187,7 @@ 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 = util.CaselessDict() + self._devices = CaselessDict() def devices(self): return self._devices @@ -217,11 +217,11 @@ return getattr(self._info, name) -class TaurusDevTree(util.CaselessDict): +class TaurusDevTree(CaselessDict): def __init__(self, other=None): super(TaurusDevTree, self).__init__() - self._devices = util.CaselessDict() + self._devices = CaselessDict() if other is not None: self._update(other) @@ -240,11 +240,11 @@ def addDevice(self, dev_info): domain, family, member = dev_info.domain(), dev_info.family(), dev_info.member() - families = self[domain] = self.get(domain, util.CaselessDict()) - devs = self._devices[domain] = self._devices.get(domain, util.CaselessDict()) + 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, util.CaselessDict()) + families[family] = members = families.get(family, CaselessDict()) members[member] = dev_info @@ -321,7 +321,7 @@ raise RuntimeError("Must be implemented in subclass") def getDevice(self, name): - """Returns a :class:`taurus.core.TaurusDevInfo` object with information + """Returns a :class:`taurus.core.taurusdatabase.TaurusDevInfo` object with information about the given device name :param name: (str) the device name @@ -406,22 +406,22 @@ return self.serverTree().getServerNameInstances(serverName) -class TaurusDatabase(taurusmodel.TaurusModel): +class TaurusDatabase(TaurusModel): def __init__(self, complete_name, parent=None): self._descr = None - self.call__init__(taurusmodel.TaurusModel, complete_name, parent) + self.call__init__(TaurusModel, complete_name, parent) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusModel implementation #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def cleanUp(self): self.trace("[TaurusDatabase] cleanUp") - taurusmodel.TaurusModel.cleanUp(self) + TaurusModel.cleanUp(self) def getTaurusElementType(self): - import taurus.core - return taurus.core.TaurusElementType.Database + + return TaurusElementType.Database @classmethod def buildModelName(cls, parent_model, relative_name): @@ -432,8 +432,8 @@ @classmethod def getNameValidator(cls): - import taurusvalidator - return taurusvalidator.DatabaseNameValidator() + from .taurusvalidator import DatabaseNameValidator + return DatabaseNameValidator() def getDescription(self,cache=True): if self._descr is None or not cache: @@ -457,7 +457,7 @@ return obj def addListener(self, listener): - ret = taurusmodel.TaurusModel.addListener(self, listener) + ret = TaurusModel.addListener(self, listener) if not ret: return ret self.fireEvent(TaurusEventType.Change, self.getDisplayValue(), listener) diff -Nru taurus-3.0.0/lib/taurus/core/taurusdevice.py taurus-3.1.0/lib/taurus/core/taurusdevice.py --- taurus-3.0.0/lib/taurus/core/taurusdevice.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusdevice.py 2013-07-25 07:53:43.000000000 +0000 @@ -3,21 +3,21 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## @@ -29,19 +29,16 @@ __docformat__ = "restructuredtext" -import weakref -import sys - -from enums import TaurusSWDevState, TaurusEventType, LockStatus -from taurusbasetypes import TaurusLockInfo -import taurusmodel +from .taurusbasetypes import TaurusSWDevState, TaurusEventType, \ + TaurusLockInfo, TaurusElementType +from .taurusmodel import TaurusModel DFT_DEVICE_DESCRIPTION = "A device" -class TaurusDevice(taurusmodel.TaurusModel): - - SHUTDOWNS = (TaurusSWDevState.Shutdown, TaurusSWDevState.Crash, +class TaurusDevice(TaurusModel): + + SHUTDOWNS = (TaurusSWDevState.Shutdown, TaurusSWDevState.Crash, TaurusSWDevState.EventSystemShutdown) """A Device object representing an abstraction of the PyTango.DeviceProxy @@ -52,14 +49,14 @@ parent = kw.pop('parent', None) storeCallback = kw.pop('storeCallback', None) self.__dict__.update(kw) - self.call__init__(taurusmodel.TaurusModel, name, parent) - + self.call__init__(TaurusModel, name, parent) + self._deviceObj = self._createHWObject() self._deviceStateObj = None self._lock_info = TaurusLockInfo() self._descr = None self._deviceSwState = self.decode(TaurusSWDevState.Uninitialized) - + if storeCallback: storeCallback(self) @@ -71,15 +68,21 @@ if not self._deviceStateObj is None: self._deviceStateObj.removeListener(self) self._deviceStateObj = None - taurusmodel.TaurusModel.cleanUp(self) + TaurusModel.cleanUp(self) # Export the DeviceProxy interface into this object. # This way we can call for example read_attribute on an object of this class def __getattr__(self, name): - if not self._deviceObj is None: - return getattr(self._deviceObj,name) - return None - + if '_deviceObj' in self.__dict__ and self._deviceObj is not None: + return getattr(self._deviceObj, name) + cls_name = self.__class__.__name__ + raise AttributeError("'%s' has no attribute '%s'" % (cls_name, name)) + + #def __setattr__(self, name, value): + # if '_deviceObj' in self.__dict__ and self._deviceObj is not None: + # return setattr(self._deviceObj, name, value) + # super(TaurusDevice, self).__setattr__(name, value) + # Export the 'act like dictionary' feature of PyTango.DeviceProxy def __getitem__(self, key): attr = self.getAttribute(key) @@ -94,10 +97,10 @@ if hw is None: return False return hw.__contains__(key) - + def getHWObj(self): return self._deviceObj - + def getStateObj(self): if self._deviceStateObj is None: self._deviceStateObj = self.factory().getAttribute("%s/state" % self.getFullName()) @@ -108,13 +111,13 @@ if not stateAttrValue is None: return stateAttrValue.value return None - + def getSWState(self, cache=True): return self.getValueObj(cache=cache).value def getAttribute(self, attrname): """Returns the attribute object given its name""" - + slashnb = attrname.count('/') if slashnb == 0: attrname = "%s/%s" % (self.getFullName(), attrname) @@ -122,10 +125,10 @@ attrname = "%s%s" % (self.getFullName(), attrname) import taurusattribute return self.factory().getObject(taurusattribute.TaurusAttribute,attrname) - + def isValidDev(self): """returns True if the device is in "working conditions - + The default implementation always returns True. Reimplement it in subclasses if there are cases in which the device cannot be queried (e.g. in Tango, the TangoDevice object may exist even if there is not a real @@ -144,23 +147,22 @@ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # Mandatory implementation in sub class - #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- - + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + def _createHWObject(self): raise NotImplementedError #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # TaurusModel implementation - #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def getTaurusElementType(self): - import taurus.core - return taurus.core.TaurusElementType.Device - + return TaurusElementType.Device + @classmethod def buildModelName(cls, parent_model, relative_name): """build an 'absolute' model name from the parent model and the 'relative' - name. + name. - If parent_model is a TaurusDatabase, the return is a composition of the database model name and is device name - If parent_model is a TaurusDevice, the relative name is ignored and @@ -173,8 +175,8 @@ return relative_name if isinstance(parent_model, cls): return parent_name - return '%s/%s' % (parent_name,relative_name) - + return '%s/%s' % (parent_name,relative_name) + @classmethod def getNameValidator(cls): import taurusvalidator @@ -184,11 +186,11 @@ if not self.hasListeners() or not cache: try: v = self.getStateObj().read(cache=cache) - except Exception: - v = sys.exc_info()[1] + except Exception as e: + v = e self._deviceSwState = self.decode(v) return self._deviceSwState - + def getDisplayValue(self,cache=True): return TaurusSWDevState.whatis(self.getValueObj(cache).value) @@ -201,7 +203,7 @@ obj.append(('device state', self.getStateObj().getDisplayValue()) or self.getNoneValue()) obj.append(('SW state', self.getDisplayValue())) return obj - + def getDescription(self,cache=True): if self._descr is None or not cache: try: @@ -209,29 +211,29 @@ except: self._descr = self._getDefaultDescription() return self._descr - + def removeListener(self, listener): - ret = taurusmodel.TaurusModel.removeListener(self, listener) + ret = TaurusModel.removeListener(self, listener) if not ret or self.hasListeners(): return ret # False, None or True return self.getStateObj().removeListener(self) - + def addListener(self, listener): weWereListening = self.hasListeners() - ret = taurusmodel.TaurusModel.addListener(self, listener) + ret = TaurusModel.addListener(self, listener) if not ret: return ret - + # We are only listening to State if someone is listening to us if weWereListening: # We were listening already, so we must fake an event to the new - # subscrived listener with the current value - self.fireEvent(taurusmodel.TaurusEventType.Change, self.getValueObj(), hasattr(listener,'__iter__') and listener or [listener]) + # subscribed listener with the current value + self.fireEvent(TaurusEventType.Change, self.getValueObj(), hasattr(listener,'__iter__') and listener or [listener]) else: # We were not listening to events, but now we have to self.getStateObj().addListener(self) return ret - + def getChildObj(self, child_name): if child_name is None or len(child_name) == 0: return None @@ -254,7 +256,7 @@ return DFT_DEVICE_DESCRIPTION def poll(self, attrs): - '''Polling certain attributes of the device. This default + '''Polling certain attributes of the device. This default implementation simply polls each attribute one by one''' for attr in attrs.values(): attr.poll() diff -Nru taurus-3.0.0/lib/taurus/core/taurusexception.py taurus-3.1.0/lib/taurus/core/taurusexception.py --- taurus-3.0.0/lib/taurus/core/taurusexception.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusexception.py 2013-07-25 07:53:43.000000000 +0000 @@ -30,10 +30,14 @@ __docformat__ = "restructuredtext" class TaurusException(Exception): + def __init__(self, description, code = None): - Exception.__init__(self, description, code) + #Exception.__init__(self, description, code) self.code = code self.description = description - + + def __str__(self): + return str(self.description) + class DoubleRegistration(TaurusException): - pass \ No newline at end of file + pass diff -Nru taurus-3.0.0/lib/taurus/core/taurusfactory.py taurus-3.1.0/lib/taurus/core/taurusfactory.py --- taurus-3.0.0/lib/taurus/core/taurusfactory.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusfactory.py 2013-07-25 07:53:43.000000000 +0000 @@ -41,11 +41,11 @@ __docformat__ = "restructuredtext" -from enums import OperationMode -import taurusdatabase -import taurusdevice -import taurusattribute -import taurusconfiguration +from .taurusbasetypes import OperationMode +from .taurusdatabase import TaurusDatabase +from .taurusdevice import TaurusDevice +from .taurusattribute import TaurusAttribute +from .taurusconfiguration import TaurusConfiguration, TaurusConfigurationProxy class TaurusFactory(object): """The base class for valid Factories in Taurus.""" @@ -85,20 +85,20 @@ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def findObjectClass(self, absolute_name): - """findObjectClass(string absolute_name) -> taurus.core.TaurusModel subclass + """findObjectClass(string absolute_name) -> taurus.core.taurusmodel.TaurusModel subclass Obtain the class object corresponding to the given name. @param[in] absolute_name the object absolute name string - @return a class object that should be a subclass of a taurus.core.TaurusModel + @return a class object that should be a subclass of a taurus.core.taurusmodel.TaurusModel @throws TaurusException if the given name is invalid. """ raise RuntimeError("findObjectClass cannot be called for abstract" \ " TaurusFactory") def getDatabase(self, db_name=None): - """getDatabase(string db_name) -> taurus.core.TaurusDatabase + """getDatabase(string db_name) -> taurus.core.taurusdatabase.TaurusDatabase Obtain the object corresponding to the given database name or the default database if db_name is None. @@ -106,37 +106,37 @@ instance is returned. Otherwise a new instance is stored and returned. @param[in] db_name database name string. It should be formed like: - ://. If is ommited then - it will use the default schema. if db_name is None, + ://. If is ommited then + it will use the default scheme. if db_name is None, the default database is used - @return a taurus.core.TaurusDatabase object + @return a taurus.core.taurusdatabase.TaurusDatabase object @throws TaurusException if the given name is invalid. """ raise RuntimeError("getDatabase cannot be called for abstract" \ " TaurusFactory") def getDevice(self, dev_name, **kw): - """getDevice(string dev_name) -> taurus.core.TaurusDevice + """getDevice(string dev_name) -> taurus.core.taurusdevice.TaurusDevice Obtain the object corresponding to the given device name. If the corresponding device already exists, the existing instance is returned. Otherwise a new instance is stored and returned. @param[in] dev_name the device name string. It should be formed like: - :///. If - is ommited then it will use the default schema. + :///. If + is ommited then it will use the default scheme. If authority is ommited then it will use the - default authority for the schema. + default authority for the scheme. - @return a taurus.core.TaurusDevice object + @return a taurus.core.taurusdevice.TaurusDevice object @throws TaurusException if the given name is invalid. """ raise RuntimeError("getDevice cannot be called for abstract" \ " TaurusFactory") def getAttribute(self, attr_name): - """getAttribute(string attr_name) -> taurus.core.TaurusAttribute + """getAttribute(string attr_name) -> taurus.core.taurusattribute.TaurusAttribute Obtain the object corresponding to the given attribute name. If the corresponding attribute already exists, the existing instance @@ -144,22 +144,22 @@ @param[in] attr_name string attribute name - @return a taurus.core.TaurusAttribute object + @return a taurus.core.taurusattribute.TaurusAttribute object @throws TaurusException if the given name is invalid. """ raise RuntimeError("getAttribute cannot be called for abstract" \ " TaurusFactory") def getConfiguration(self, param): - """getConfiguration(param) -> taurus.core.TaurusConfiguration + """getConfiguration(param) -> taurus.core.taurusconfiguration.TaurusConfiguration 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[in] param taurus.core.TaurusAttribute object or full configuration name + @param[in] param taurus.core.taurusattribute.TaurusAttribute object or full configuration name - @return a taurus.core.TaurusAttribute object + @return a taurus.core.taurusattribute.TaurusAttribute object @throws TaurusException if the given name is invalid. """ raise RuntimeError("getConfiguration cannot be called for abstract" \ @@ -209,15 +209,15 @@ return obj def getObject(self, cls, name): - if issubclass(cls, taurusdatabase.TaurusDatabase): + if issubclass(cls, TaurusDatabase): return self.getDatabase(name) - elif issubclass(cls, taurusdevice.TaurusDevice): + elif issubclass(cls, TaurusDevice): return self.getDevice(name) - elif issubclass(cls, taurusattribute.TaurusAttribute): + elif issubclass(cls, TaurusAttribute): return self.getAttribute(name) - elif issubclass(cls, taurusconfiguration.TaurusConfiguration): + elif issubclass(cls, TaurusConfiguration): return self.getConfiguration(name) - elif issubclass(cls, taurusconfiguration.TaurusConfigurationProxy): + elif issubclass(cls, TaurusConfigurationProxy): return self.getConfiguration(name) else: return None @@ -271,3 +271,9 @@ """ raise RuntimeError("removeAttributeFromPolling cannot be called for abstract" \ " TaurusFactory") + + def __str__(self): + return '{0}()'.format(self.__class__.__name__) + + def __repr__(self): + return '{0}(schemes={1})'.format(self.__class__.__name__, ", ".join(self.schemes)) diff -Nru taurus-3.0.0/lib/taurus/core/taurushelper.py taurus-3.1.0/lib/taurus/core/taurushelper.py --- taurus-3.0.0/lib/taurus/core/taurushelper.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurushelper.py 2013-07-25 07:53:43.000000000 +0000 @@ -25,6 +25,16 @@ """a list of helper methods""" +__all__ = ['check_dependencies', 'log_dependencies', 'getSchemeFromName', + 'Manager', 'Factory', 'Device', 'Attribute', 'Configuration', + 'Database', 'Object', 'Logger', + 'Critical', 'Error', 'Warning', 'Info', 'Debug', 'Trace', + 'setLogLevel', 'setLogFormat', 'getLogLevel', 'getLogFormat', + 'resetLogLevel', 'resetLogFormat', + 'enableLogOutput', 'disableLogOutput', + 'log', 'trace', 'debug', 'info', 'warning', 'error', 'critical', + 'changeDefaultPollingPeriod'] + __docformat__ = "restructuredtext" import sys @@ -62,7 +72,7 @@ try: v += int(parts[0]) l -= 1 - except ValueError,ve: + except ValueError: return v if not l: return v @@ -167,7 +177,7 @@ print m def log_dependencies(): - from taurus.core.util import Logger + from taurus.core.util.log import Logger l = Logger("taurus") for msg in _check_dependencies(forlog=True): if msg[0] != -1: @@ -295,32 +305,37 @@ It is a shortcut to:: import taurus.core - manager = taurus.core.TaurusManager() + manager = taurus.core.taurusmanager.TaurusManager() :return: the TaurusManager - :rtype: :class:`taurus.core.TaurusManager` + :rtype: :class:`taurus.core.taurusmanager.TaurusManager` - .. seealso:: :class:`taurus.core.TaurusManager`""" - import taurusmanager - return taurusmanager.TaurusManager() + .. seealso:: :class:`taurus.core.taurusmanager.TaurusManager`""" + from taurus.core.taurusmanager import TaurusManager + return TaurusManager() def Factory(scheme=None): """Returns the one and only Factory for the given scheme It is a shortcut to:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory(scheme) :param scheme: a string representing the scheme. Default value is None meaning ``tango`` scheme :type scheme: str :return: a taurus factory - :rtype: :class:`taurus.core.TaurusFactory`""" - f = Manager().getFactory(scheme=scheme) + :rtype: :class:`taurus.core.taurusfactory.TaurusFactory`""" + manager = Manager() + f = manager.getFactory(scheme=scheme) if f is None: - import taurusexception - raise taurusexception.TaurusException('Cannot create Factory for scheme %s'%repr(scheme)) + from taurus.core.taurusexception import TaurusException + if scheme is None: + scheme = "default scheme '" + manager.default_scheme + "'" + else: + scheme = "'" + scheme + "'" + raise TaurusException('Cannot create Factory for %s' % scheme) return f() def Device(device_name): @@ -328,15 +343,15 @@ It is a shortcut to:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory() device = factory.getDevice(device_name) :param device_name: the device name :type device_name: str :return: a taurus device - :rtype: :class:`taurus.core.TaurusDevice`""" + :rtype: :class:`taurus.core.taurusdevice.TaurusDevice`""" return Factory(scheme=getSchemeFromName(device_name)).getDevice(device_name) def Attribute(dev_or_attr_name, attr_name=None): @@ -348,15 +363,15 @@ It is a shortcut to:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory() attribute = factory.getAttribute(full_attribute_name) or:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory() device = factory.getDevice(device_name) attribute = device.getAttribute(attribute_name) @@ -366,7 +381,7 @@ :param attr_name: attribute name :type attr_name: str :return: a taurus attribute - :rtype: :class:`taurus.core.TaurusAttribute`""" + :rtype: :class:`taurus.core.taurusattribute.TaurusAttribute`""" import types if attr_name is None: @@ -387,15 +402,15 @@ It is a shortcut to:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory() conf = factory.getConfiguration(attr_or_conf_name) or:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory() attribute = factory.getAttribute(attribute_name) conf = attribute.getConfig(conf_name) @@ -405,7 +420,7 @@ :param conf_name: conf name :type conf_name: str or None :return: a taurus configuration - :rtype: :class:`taurus.core.TaurusConfiguration`""" + :rtype: :class:`taurus.core.taurusconfiguration.TaurusConfiguration`""" if conf_name is None: return Factory(scheme=getSchemeFromName(attr_or_conf_name)).getConfiguration(attr_or_conf_name) else: @@ -416,15 +431,15 @@ It is a shortcut to:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory() db = factory.getDatabase(db_name) :param db_name: database name. If None (default) it will use the TANGO_HOST value :type db_name: str or None :return: a taurus database - :rtype: :class:`taurus.core.TaurusDatabase`""" + :rtype: :class:`taurus.core.taurusdatabase.TaurusDatabase`""" return Factory(getSchemeFromName(db_name)).getDatabase(db_name) def Object(klass, name): @@ -432,8 +447,8 @@ It is a shortcut to:: - import taurus.core - manager = taurus.core.TaurusManager() + import taurus.core.taurusmanager + manager = taurus.core.taurusmanager.TaurusManager() factory = manager.getFactory() obj = factory.getObject(klass, name) @@ -442,48 +457,39 @@ :param name: the full object name :type name: str :return: a taurus object - :rtype: :class:`taurus.core.TaurusModel`""" + :rtype: :class:`taurus.core.taurusmodel.TaurusModel`""" return Factory(getSchemeFromName(name)).getObject(klass, name) -import util +from taurus.core.util import log as __log_mod -Critical = util.Logger.Critical -Error = util.Logger.Error -Warning = util.Logger.Warning -Info = util.Logger.Info -Debug = util.Logger.Debug -Trace = util.Logger.Trace - -setLogLevel = util.Logger.setLogLevel -setLogFormat = util.Logger.setLogFormat -getLogLevel = util.Logger.getLogLevel -getLogFormat = util.Logger.getLogFormat -resetLogLevel = util.Logger.resetLogLevel -resetLogFormat = util.Logger.resetLogFormat - -enableLogOutput = util.Logger.enableLogOutput -disableLogOutput = util.Logger.disableLogOutput - -def log(level, msg, *args, **kw): - return util.Logger.getRootLog().log(level, msg, *args, **kw) - -def trace(msg, *args, **kw): - return log(Trace, msg, *args, **kw) - -def debug(msg, *args, **kw): - return util.Logger.getRootLog().debug(msg, *args, **kw) - -def info(msg, *args, **kw): - return util.Logger.getRootLog().info(msg, *args, **kw) - -def warning(msg, *args, **kw): - return util.Logger.getRootLog().warning(msg, *args, **kw) - -def error(msg, *args, **kw): - return util.Logger.getRootLog().error(msg, *args, **kw) - -def critical(msg, *args, **kw): - return util.Logger.getRootLog().critical(msg, *args, **kw) +Logger = __log_mod.Logger +Critical = Logger.Critical +Error = Logger.Error +Warning = Logger.Warning +Info = Logger.Info +Debug = Logger.Debug +Trace = Logger.Trace + +setLogLevel = Logger.setLogLevel +setLogFormat = Logger.setLogFormat +getLogLevel = Logger.getLogLevel +getLogFormat = Logger.getLogFormat +resetLogLevel = Logger.resetLogLevel +resetLogFormat = Logger.resetLogFormat + +enableLogOutput = Logger.enableLogOutput +disableLogOutput = Logger.disableLogOutput + +log = __log_mod._log +trace = __log_mod.trace +debug = __log_mod.debug +info = __log_mod.info +warning = __log_mod.warning +error = __log_mod.error +critical = __log_mod.critical def changeDefaultPollingPeriod(period): - Manager().changeDefaultPollingPeriod(period) \ No newline at end of file + Manager().changeDefaultPollingPeriod(period) + +#del __log_mod +#del __translate_version_str2int \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/core/tauruslistener.py taurus-3.1.0/lib/taurus/core/tauruslistener.py --- taurus-3.0.0/lib/taurus/core/tauruslistener.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tauruslistener.py 2013-07-25 07:53:43.000000000 +0000 @@ -29,15 +29,13 @@ __docformat__ = "restructuredtext" -import PyTango +from .util.log import Logger -import util - -class TaurusListener(util.Logger): +class TaurusListener(Logger): """ TaurusListener Interface""" def __init__(self, name, parent=None): - self.call__init__(util.Logger, name, parent) + self.call__init__(Logger, name, parent) def eventReceived(self, src, type, evt_value): """ Method to implement the event notification""" @@ -49,9 +47,7 @@ class TaurusExceptionListener(object): - """Class for handling ConnectionFailed, DevFailed and TaurusException exceptions. - - The TaurusExceptionListeners are invoked when the """ + """Class for handling ConnectionFailed, DevFailed and TaurusException exceptions.""" def connectionFailed(self, ex): self._printException(ex) @@ -60,6 +56,7 @@ self._printException(self) def exceptionReceived(self, exception): + import PyTango if isinstance(exception, PyTango.ConnectionFailed): self.connectionFailed(exception) @@ -67,7 +64,7 @@ self.devFailed(exception) else: - self._printException(self, exception) + self._printException(exception) def _printException(self, exception): print self.__class__.__name__, "received", exception.__class__.__name__, str(exception) diff -Nru taurus-3.0.0/lib/taurus/core/taurusmanager.py taurus-3.1.0/lib/taurus/core/taurusmanager.py --- taurus-3.0.0/lib/taurus/core/taurusmanager.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusmanager.py 2013-07-25 07:53:43.000000000 +0000 @@ -29,23 +29,32 @@ __docformat__ = "restructuredtext" -import os, imp, atexit +import os +import imp +import atexit + +from .util.singleton import Singleton +from .util.log import Logger +from .util.threadpool import ThreadPool + +from .taurusbasetypes import OperationMode, ManagerState, TaurusSerializationMode +from .taurusdatabase import TaurusDatabase +from .taurusdevice import TaurusDevice +from .taurusconfiguration import TaurusConfiguration +from .taurusexception import TaurusException +from .taurusfactory import TaurusFactory -import util -import taurus.core -from enums import OperationMode, ManagerState, TaurusSerializationMode -from taurus.core.taurusexception import TaurusException - -class TaurusManager(util.Singleton, util.Logger): - """A :class:`taurus.core.util.Singleton` class designed to provide Taurus management. +class TaurusManager(Singleton, Logger): + """A :class:`taurus.core.util.singleton.Singleton` class designed to provide Taurus management. Example:: - >>> import taurus.core - >>> manager = taurus.core.TaurusManager() - >>> print manager == taurus.core.TaurusManager() + >>> import taurus.core.taurusmanager + >>> manager = taurus.core.taurusmanager.TaurusManager() + >>> print manager == taurus.core.taurusmanager.TaurusManager() True """ + PLUGIN_KEY = "__taurus_plugin__" DefaultSerializationMode = TaurusSerializationMode.Concurrent default_scheme = "tango" @@ -58,7 +67,7 @@ """Singleton instance initialization. For internal usage only. Do **NOT** call this method directly""" self._state = ManagerState.UNINITIALIZED - self.call__init__(util.Logger) + self.call__init__(Logger) self.reInit() atexit.register(self.cleanUp) @@ -73,16 +82,15 @@ self._operation_mode = OperationMode.ONLINE self._serialization_mode = self.DefaultSerializationMode if self._serialization_mode == TaurusSerializationMode.Concurrent: - self._thread_pool = util.ThreadPool(name="TaurusTP", - parent=self, - Psize=5, - Qsize=1000) + self._thread_pool = ThreadPool(name="TaurusTP", + parent=self, + Psize=5, + Qsize=1000) else: self._thread_pool = None - self._plugins = self._build_plugins() + self._plugins = None self._initial_default_scheme = self.default_scheme - self._default_factory = self._plugins.get(self.default_scheme, None) self._state = ManagerState.INITED @@ -95,7 +103,7 @@ if self._plugins is None: return self.trace("[TaurusManager] cleanUp") - for f_schema, f in self._plugins.items(): + for f_scheme, f in self._plugins.items(): f().cleanUp() self._plugins = None @@ -144,10 +152,9 @@ self.default_scheme = "simulation" else: self.default_scheme = self._initial_default_scheme - self._default_factory = self._plugins.get(self.default_scheme, None) self._operation_mode = mode - for plugin in self._plugins.values(): + for plugin in self.getPlugins().values(): plugin().setOperationMode(mode) def getOperationMode(self): @@ -159,34 +166,36 @@ def getDefaultFactory(self): """Gives the default factory. - :return: (taurus.core.TaurusFactory) the default taurus factory + :return: (taurus.core.taurusfactory.TaurusFactory) the default taurus factory """ - return self._default_factory + return self.getPlugins().get(self.default_scheme, None) def getPlugins(self): """Gives the information about the existing plugins - :return: (dict)the list of plugins + :return: (dict)the list of plugins """ + if self._plugins is None: + self._plugins = self._build_plugins() return self._plugins def getFactory(self, scheme=None): """Gives the factory class object supporting the given scheme :param scheme: (str or None) the scheme. If None the default scheme is used - :return: (taurus.core.TaurusFactory or None) the factory class object for the + :return: (taurus.core.taurusfactory.TaurusFactory or None) the factory class object for the given scheme or None if a proper factory is not found """ if scheme is None: return self.getDefaultFactory() - return self._plugins.get(scheme) + return self.getPlugins().get(scheme) def getObject(self, cls, name): """Gives the object for the given class with the given name - :param cls: (taurus.core.TaurusModel) object class + :param cls: (taurus.core.taurusmodel.TaurusModel) object class :param name: (str) the object name - :return: (taurus.core.TaurusModel or None) a taurus model object + :return: (taurus.core.taurusmodel.TaurusModel or None) a taurus model object """ factory = self._get_factory(name) if factory is None: return @@ -196,7 +205,7 @@ """Finds the object with the given name :param absolute_name: (str) the object name - :return: (taurus.core.TaurusModel or None) the taurus model object or None if + :return: (taurus.core.taurusmodel.TaurusModel or None) the taurus model object or None if no suitable name found """ factory = self._get_factory(absolute_name) @@ -207,7 +216,7 @@ """Finds the object class for the given object name :param absolute_name: (str) the object name - :return: (class taurus.core.TaurusModel or None) the taurus model class object or + :return: (class taurus.core.taurusmodel.TaurusModel or None) the taurus model class object or None if no suitable name found """ factory = self._get_factory(absolute_name) @@ -218,50 +227,50 @@ """Returns a database object for the given name :param name: (str) database name - :return: (taurus.core.TaurusDatabase) the database for the given name + :return: (taurus.core.taurusdatabase.TaurusDatabase) the database for the given name """ - return self.getObject(taurus.core.TaurusDatabase, name) + return self.getObject(TaurusDatabase, name) def getDevice(self, name): """Returns a device object for the given name :param name: (str) device name - :return: (taurus.core.TaurusDevice) the device for the given name + :return: (taurus.core.taurusdevice.TaurusDevice) the device for the given name """ - return self.getObject(taurus.core.TaurusDevice, name) + return self.getObject(TaurusDevice, name) def getAttribute(self, name): """Returns a attribute object for the given name :param name: (str) attribute name - :return: (taurus.core.TaurusAttribute) the attribute for the given name + :return: (taurus.core.taurusattribute.TaurusAttribute) the attribute for the given name """ - return self.getObject(taurus.core.TaurusAttribute, name) + return self.getObject(TaurusAttribute, name) def getConfiguration(self, name): """Returns a configuration object for the given name :param name: (str) configuration name - :return: (taurus.core.TaurusConfiguration) the configuration for the given name + :return: (taurus.core.taurusconfiguration.TaurusConfiguration) the configuration for the given name """ - return self.getObject(taurus.core.TaurusConfiguration, name) + return self.getObject(TaurusConfiguration, name) def _get_factory(self, name): - scheme = self._get_schema(name) + scheme = self._get_scheme(name) if scheme is None: return try: - return self._plugins[scheme]() + return self.getPlugins()[scheme]() except: raise TaurusException('Invalid scheme "%s"'%scheme) - def _get_schema(self, name): + def _get_scheme(self, name): try: return name[:name.index('://')] except ValueError, e: - if self._default_factory is None: - self.warning("scheme not found for %s" % name) - return return self.default_scheme + + def _get_schema(self, name): + raise DeprecationWarning('_get_schema is deprecated. Use _get_scheme instead') def _build_plugins(self): plugin_classes = self._get_plugin_classes() @@ -282,37 +291,43 @@ import taurusfactory upgrade_classes = [] - files = os.listdir(self._this_path) + elems = os.listdir(self._this_path) dirs = [] - for f in files: - if f.startswith('.') or f == 'util': + for elem in elems: + if elem.startswith('.') or elem.startswith("_"): continue - f = os.path.join(self._this_path, f) - if os.path.isdir(f): - elems = os.listdir(f) - if '__init__.py' in elems: - dirs.append(f) + elem = os.path.join(self._this_path, elem) + if not os.path.isdir(elem): + continue + plugin_file = os.path.join(elem, self.PLUGIN_KEY) + if not os.path.exists(plugin_file): + continue + if not os.path.exists(os.path.join(elem, '__init__.py')): + continue + dirs.append(elem) plugins = [] - for d in dirs: - package_name = d.split(os.path.sep)[-1] + full_module_names = ['taurus.core.%s'%d.split(os.path.sep)[-1] for d in dirs] + from taurus import tauruscustomsettings + full_module_names.extend(getattr(tauruscustomsettings,'EXTRA_SCHEME_MODULES',[])) + + for full_module_name in full_module_names: try: - full_module_name = 'taurus.core.%s' % package_name m = __import__(full_module_name, fromlist=['*'], level=0) except Exception, imp1: # just in case we are in python 2.4 try: m = __import__(full_module_name, globals(), locals(), ['*']) except: - self.debug('Failed to inspect %s' % (package_name)) - self.traceback() + self.debug('Failed to inspect %s' % (full_module_name)) + self.debug('Details:', exc_info=1) continue for s in m.__dict__.values(): plugin = None try: - if issubclass(s, taurus.core.TaurusFactory) and \ - issubclass(s, util.Singleton): + if issubclass(s, TaurusFactory) and \ + issubclass(s, Singleton): if hasattr(s, 'schemes') : schemes = getattr(s, 'schemes') if len(schemes): @@ -327,7 +342,6 @@ if not plugin is None: self.debug('Found plugin %s' % plugin.__name__) plugins.append(plugin) - return plugins def _find_scheme(self, factory_class): @@ -340,7 +354,7 @@ """Executes the given operations :param ops: the sequence of operations - :type ops: sequence""" + :type ops: sequence""" for o in ops: o.execute() @@ -348,7 +362,16 @@ self.getFactory()().changeDefaultPollingPeriod(period) # todo: go through all known plugin factories and change their polling # period + + def __str__name__(self, name): + return '{0}({1})'.format(self.__class__.__name__, name) + def __str__(self): + return self.__str__name__("") + + def __repr__(self): + return self.__str__name__("") + if __name__ == '__main__': manager = TaurusManager() print manager.getPlugins() diff -Nru taurus-3.0.0/lib/taurus/core/taurusmodel.py taurus-3.1.0/lib/taurus/core/taurusmodel.py --- taurus-3.0.0/lib/taurus/core/taurusmodel.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusmodel.py 2013-07-25 07:53:43.000000000 +0000 @@ -33,10 +33,11 @@ import operator import threading -import util -from enums import TaurusEventType, MatchLevel +from .util.log import Logger +from .util.event import CallableRef, BoundMethodWeakref +from .taurusbasetypes import TaurusEventType, MatchLevel -class TaurusModel(util.Logger): +class TaurusModel(Logger): RegularEvent = (TaurusEventType.Change, TaurusEventType.Config, TaurusEventType.Periodic) @@ -48,7 +49,7 @@ self.trace("invalid name") name = self._simp_name or self._norm_name or self._full_name or 'TaurusModel' - self.call__init__(util.Logger, name, parent) + self.call__init__(Logger, name, parent) if serializationMode is None: s_obj = parent @@ -63,18 +64,20 @@ self._parentObj = None self._listeners = [] + def __str__name__(self, name): + return '{0}({1})'.format(self.__class__.__name__, name) + def __str__(self): - return '%s(%s)' % (self.__class__.__name__, self.getSimpleName()) + return self.__str__name__(self.getNormalName()) def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, self.getFullName()) + return self.__str__name__(self.getFullName()) - def cleanUp(self): self.trace("[TaurusModel] cleanUp") #self._parentObj = None self._listeners = None - util.Logger.cleanUp(self) + Logger.cleanUp(self) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- # API for Factory access @@ -184,7 +187,7 @@ if meth is not None and operator.isCallable(meth): return weakref.ref(listener, cb) else: - return util.CallableRef(listener, cb) + return CallableRef(listener, cb) def addListener(self, listener): if self._listeners is None or listener is None: @@ -242,7 +245,7 @@ listeners = listeners, for listener in listeners: - if isinstance(listener, weakref.ref) or isinstance(listener, util.BoundMethodWeakref): + if isinstance(listener, weakref.ref) or isinstance(listener, BoundMethodWeakref): l = listener() else: l = listener diff -Nru taurus-3.0.0/lib/taurus/core/taurusoperation.py taurus-3.1.0/lib/taurus/core/taurusoperation.py --- taurus-3.0.0/lib/taurus/core/taurusoperation.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusoperation.py 2013-07-25 07:53:43.000000000 +0000 @@ -3,21 +3,21 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## @@ -29,52 +29,52 @@ __docformat__ = "restructuredtext" -import util +from .util.log import Logger + +class TaurusOperation(Logger): -class TaurusOperation(util.Logger): - def __init__(self, name='TaurusOperation', parent=None, callbacks = None): - self.call__init__(util.Logger, name, parent) + self.call__init__(Logger, name, parent) if callbacks is None: callbacks = [] self._callbacks = callbacks self._dangerMessage = None self._isDangerous = False - + def getDevice(self): pass - + def setCallbacks(self, callbacks): self._callbacks = callbacks - + def getCallbacks(self): - return self._callbacks - + return self._callbacks + def execute(self): for f in self._callbacks: f(operation = self) - + def isDangerous(self): return self._isDangerous - + def setDangerMessage(self, dangerMessage=None): '''if dangerMessage is None, the operation is considered safe''' self._dangerMessage = dangerMessage self._isDangerous = dangerMessage is not None - + def getDangerMessage(self): return self._dangerMessage - + def resetDangerMessage(self): self.setDangerMessage(None) - - + + class WriteAttrOperation(TaurusOperation): - + def __init__(self, attr, value, callbacks = None): self.call__init__(TaurusOperation, 'WriteAttrOperation', attr, callbacks=callbacks) self.attr = attr self.value = value - + def execute(self): self.attr.write(self.value) TaurusOperation.execute(self) diff -Nru taurus-3.0.0/lib/taurus/core/tauruspollingtimer.py taurus-3.1.0/lib/taurus/core/tauruspollingtimer.py --- taurus-3.0.0/lib/taurus/core/tauruspollingtimer.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/tauruspollingtimer.py 2013-07-25 07:53:43.000000000 +0000 @@ -32,10 +32,12 @@ import time import threading -import util -from util import DebugIt +from .util.log import Logger, DebugIt +from .util.containers import CaselessDict +from .util.timer import Timer -class TaurusPollingTimer(util.Logger): + +class TaurusPollingTimer(Logger): """ Polling timer manages a list of attributes that have to be polled in the same period """ @@ -43,13 +45,13 @@ """Constructor :param period: (int) polling period (miliseconds) - :param parent: (util.Logger) parent object (default is None) + :param parent: (Logger) parent object (default is None) """ name = "TaurusPollingTimer[%d]" % period - self.call__init__(util.Logger, name, parent) + self.call__init__(Logger, name, parent) self.dev_dict = {} self.attr_nb = 0 - self.timer = util.Timer(period/1000.0, self._pollAttributes, self) + self.timer = Timer(period/1000.0, self._pollAttributes, self) self.lock = threading.RLock() def start(self): @@ -63,7 +65,7 @@ def containsAttribute(self,attribute): """Determines if the polling timer already contains this attribute - :param attribute: (taurus.core.TaurusAttribute) the attribute + :param attribute: (taurus.core.taurusattribute.TaurusAttribute) the attribute :return: (bool) True if the attribute is registered for polling or False otherwise @@ -86,7 +88,7 @@ def addAttribute(self,attribute, auto_start=True): """Registers the attribute in this polling. - :param attribute: (taurus.core.TaurusAttribute) the attribute to be added + :param attribute: (taurus.core.taurusattribute.TaurusAttribute) the attribute to be added :param auto_start: (bool) if True (default) it tells the polling timer that it should startup as soon as there is at least one attribute registered. @@ -96,7 +98,7 @@ try: attr_dict = self.dev_dict.get(dev) if attr_dict is None: - self.dev_dict[dev] = attr_dict = util.CaselessDict() + self.dev_dict[dev] = attr_dict = CaselessDict() if not attr_dict.has_key(attr_name): attr_dict[attr_name] = attribute self.attr_nb += 1 @@ -113,7 +115,7 @@ attributes decreses to 0 the polling is stopped automatically in order to save resources. - :param attribute: (taurus.core.TaurusAttribute) the attribute to be added + :param attribute: (taurus.core.taurusattribute.TaurusAttribute) the attribute to be added """ dev, attr_name = attribute.getParentObj(), attribute.getSimpleName() self.lock.acquire() diff -Nru taurus-3.0.0/lib/taurus/core/taurusvalidator.py taurus-3.1.0/lib/taurus/core/taurusvalidator.py --- taurus-3.0.0/lib/taurus/core/taurusvalidator.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/taurusvalidator.py 2013-07-25 07:53:43.000000000 +0000 @@ -33,8 +33,8 @@ import re -import util -from enums import MatchLevel +from .taurusbasetypes import MatchLevel +from .util.singleton import Singleton InvalidAlias = "nada" @@ -89,7 +89,7 @@ return None -class DatabaseNameValidator(util.Singleton, AbstractTangoValidator): +class DatabaseNameValidator(Singleton, AbstractTangoValidator): protocol_prefix = '((?Ptango)://)?' @@ -122,7 +122,7 @@ return 3*('%s:%s' % (host,port),) -class DatabaseQueryValidator(util.Singleton, AbstractTangoValidator): +class DatabaseQueryValidator(Singleton, AbstractTangoValidator): """Deprecated""" query = '\?query=(?P[\w\-_]+)(?P(\?param=[\w\*\?\%\-_]+)*)' @@ -152,7 +152,7 @@ return str, normal, short -class DeviceNameValidator(util.Singleton, AbstractTangoValidator): +class DeviceNameValidator(Singleton, AbstractTangoValidator): w = AbstractTangoValidator.tango_word dev = '(?P' + w + '/' + w + '/' + w + ')' @@ -204,7 +204,7 @@ return complete, dev_name, alias -class DeviceQueryValidator(util.Singleton, AbstractTangoValidator): +class DeviceQueryValidator(Singleton, AbstractTangoValidator): """Deprecated""" query = DatabaseQueryValidator.query @@ -233,7 +233,7 @@ return str,short -class AttributeNameValidator(util.Singleton, AbstractTangoValidator): +class AttributeNameValidator(Singleton, AbstractTangoValidator): w = AbstractTangoValidator.tango_word attr = '/(?P' + w + ')' @@ -270,7 +270,7 @@ return str, normal_name, attr_name -class ConfigurationNameValidator(util.Singleton, AbstractTangoValidator): +class ConfigurationNameValidator(Singleton, AbstractTangoValidator): w = AbstractTangoValidator.tango_word conf = "\?(?i)configuration(=(?P" + w + "))*" diff -Nru taurus-3.0.0/lib/taurus/core/util/__init__.py taurus-3.1.0/lib/taurus/core/util/__init__.py --- taurus-3.0.0/lib/taurus/core/util/__init__.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/__init__.py 2013-07-25 07:53:43.000000000 +0000 @@ -36,87 +36,11 @@ __docformat__ = "restructuredtext" -import sys -import os.path +import taurus.tauruscustomsettings -try: - import json -except: - json = None +LIGHTWEIGHT_IMPORTS = getattr(taurus.tauruscustomsettings, 'LIGHTWEIGHT_IMPORTS', False) -from .codecs import * -from .colors import * -from .constant import * -from .containers import * -from .enumeration import * -from .event import * -from .log import * -from .object import * -from .timer import * -from .singleton import * -from .safeeval import * -from .prop import * -from .threadpool import * -from .user import * - -import eventfilters - -from lxml import etree - -def str_DevFailed(df): - """Returns a string representation of a :class:`PyTango.DevFailed`. - - :param df: (PyTango.DevFailed) the PyTango exception object - :return: (str) a string representation of the given exception""" - - ret = "" - try: - desc = df.message.desc.rstrip('\n').replace('\n'," \n") - - ret += " Severity = %s\n" % df.message.severity - ret += " Reason = %s\n" % df.message.reason - ret += "Description = %s\n" % desc - ret += " Origin = %s\n" % df.message.origin - except: - ret = "Exception = %s" % str(df) - return ret - -def print_DevFailed(df): - """Prints the contents of the given :class:`PyTango.DevFailed`. - - :param df: (PyTango.DevFailed) the PyTango exception object""" - import PyTango - PyTango.Except.print_exception(df) - -def dictFromSequence(seq): - """Translates a sequence into a dictionary by converting each to elements of - the sequence (k,v) into a k:v pair in the dictionary - - :param seq: (sequence) any sequence object - :return: (dict) dictionary built from the given sequence""" - def _pairwise(iterable): - """Utility method used by dictFromSequence""" - itnext = iter(iterable).next - while True: - yield itnext(), itnext() - return dict(_pairwise(seq)) - -if sys.version_info < (2,6): - def relpath(path, start=os.path.curdir): - """Return a relative version of a path""" - - if not path: - raise ValueError("no path specified") - - start_list = os.path.abspath(start).split(os.path.sep) - path_list = os.path.abspath(path).split(os.path.sep) - - # Work out how much of the filepath is shared by start and path. - i = len(os.path.commonprefix([start_list, path_list])) - - rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] - if not rel_list: - return os.path.curdir - return os.path.join(*rel_list) - - os.path.relpath = relpath +if LIGHTWEIGHT_IMPORTS: + from init_lightweight import * +else: + from init_bkcomp import * \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/core/util/argparse/taurusargparse.py taurus-3.1.0/lib/taurus/core/util/argparse/taurusargparse.py --- taurus-3.0.0/lib/taurus/core/util/argparse/taurusargparse.py 2012-04-30 07:47:16.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/argparse/taurusargparse.py 2013-07-25 07:53:43.000000000 +0000 @@ -3,42 +3,42 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## ############################################################################# -"""Helper command line parser for taurus based on :mod:`optparse`. +"""Helper command line parser for taurus based on :mod:`optparse`. Suppose you have an application file:: - + import sys from PyQt4 import Qt - - + + class GUI(Qt.QMainWindow): pass - - + + def main(): import taurus.core.util.argparse as argparse - + parser, options, args = argparse.init_taurus_args() - + app = Qt.QApplication(sys.argv) w = GUI() w.show() @@ -46,7 +46,7 @@ if __name__ == "__main__": main() - + The call to :func:`taurus.core.util.argparse.init_taurus_args` will initialize taurus environment based on the command line options given by the user. Currently, the known options are: @@ -56,10 +56,11 @@ #. ``--tango-host`` sets the default tango host #. ``--taurus-polling-period`` sets the default taurus global polling period (milliseconds) #. ``--taurus-serialization-mode`` sets the default taurus serialization mode - + #. ``--remote-console-port`` enables remote debugging using the given port + You can easily extend the taurus options with your application specific options. -Supose you want to add an option like ``--model=``:: - +Suppose you want to add an option like ``--model=``:: + def main(): import taurus.core.util.argparse as argparse parser = argparse.get_taurus_parser(parser=parser) @@ -68,23 +69,24 @@ parser.add_option("--model") parser, options, args = argparse.init_taurus_args(parser=parser) - + app = Qt.QApplication(sys.argv) w = GUI() w.show() sys.exit(app.exec_()) """ -__all__ = ["get_taurus_parser", "init_taurus_args", "parse_taurus_args"] +__all__ = ["get_taurus_parser", "init_taurus_args", "parse_taurus_args", + "split_taurus_args"] __docformat__ = "restructuredtext" def get_taurus_parser(parser=None): - """ Returns a :class:`optparse.OptionParser` initialized with a + """ Returns a :class:`optparse.OptionParser` initialized with a :class:`optparse.OptionGroup` containning some taurus options. If a parser is given as parameter then it uses this parser instead of creating a new one. - + :param parser: an option parser or None (default) to create a new parser :type parser: :class:`optparse.OptionParser` :return: an option parser or the given parser if it is not None @@ -92,18 +94,19 @@ import optparse if parser is None: parser = optparse.OptionParser() - + g = parser.get_option_group('--taurus-log-level') if g is None: group = optparse.OptionGroup(parser, "Taurus Options", "Basic options present in any taurus application") - + help_tauruslog = "taurus log level. Allowed values are (case insensitive): critical, "\ "error, warning/warn, info, debug, trace" help_tangohost = "Tango host name" help_tauruspolling = "taurus global polling period in milliseconds" help_taurusserial= "taurus serialization mode. Allowed values are (case insensitive): "\ "serial, concurrent (default)" + help_rcport = "enables remote debugging using the given port" group.add_option("--taurus-log-level", dest="taurus_log_level", metavar="LEVEL", help=help_tauruslog, type="str", default="info") group.add_option("--taurus-polling-period", dest="taurus_polling_period", metavar="MILLISEC", @@ -112,23 +115,25 @@ help=help_taurusserial, type="str", default="Concurrent") group.add_option("--tango-host", dest="tango_host", metavar="TANGO_HOST", help=help_tangohost, type="str", default=None) + group.add_option("--remote-console-port", dest="remote_console_port", metavar="PORT", + help=help_rcport, type="int", default=None) parser.add_option_group(group) return parser - + def parse_taurus_args(parser=None, args=None, values=None): """Parses the command line. If parser is not given, then a new parser is created. In any case, the parser is initialized using the :func:`taurus.core.util.argparse.get_taurus_parser`. args and values are the optional parameters that will be given when executing :meth:`optparse.OptionParser.parse_args`. - + :param parser: an option parser or None (default) to create a new parser :type parser: :class:`optparse.OptionParser` :param args: the list of arguments to process (default is None meaning: sys.argv[1:]) :type args: seq - :param values: a :class:`optparse.Values` object to store option arguments in - (default is None meaning: a new instance of Values) - if you give an - existing object, the option defaults will not be initialized on it + :param values: a :class:`optparse.Values` object to store option arguments in + (default is None meaning: a new instance of Values) - if you give an + existing object, the option defaults will not be initialized on it :return: a tuple of three elements: parser, options, args :rtype: :class:`optparse.OptionParser`, :class:`optparse.Values`, seq """ parser = get_taurus_parser(parser=parser) @@ -137,28 +142,28 @@ def init_taurus_args(parser=None, args=None, values=None): """Parses the command line using :func:`taurus.core.util.argparse.parse_taurus_args`. - + After the command line is parsed, actions are taken on each recognized parameter. For example, the taurus log level and the default tango host are set accordingly. - + :param parser: an option parser or None (default) to create a new parser :type parser: :class:`optparse.OptionParser` :param args: the list of arguments to process (default is None meaning: sys.argv[1:]) :type args: seq - :param values: a :class:`optparse.Values` object to store option arguments in - (default is None meaning: a new instance of Values) - if you give an - existing object, the option defaults will not be initialized on it + :param values: a :class:`optparse.Values` object to store option arguments in + (default is None meaning: a new instance of Values) - if you give an + existing object, the option defaults will not be initialized on it :return: a tuple of three elements: parser, options, args :rtype: :class:`optparse.OptionParser`, :class:`optparse.Values`, seq """ import taurus parser, options, args = parse_taurus_args(parser=parser, args=args, values=values) - + # initialize taurus log level log_level_str = options.taurus_log_level.capitalize() if hasattr(taurus, log_level_str): log_level = getattr(taurus, log_level_str) taurus.setLogLevel(log_level) - + # initialize tango host if options.tango_host is not None: tango_factory = taurus.Factory("tango") @@ -170,11 +175,47 @@ # initialize taurus serialization mode if options.taurus_serialization_mode is not None: - import taurus.core + import taurus.core.taurusbasetypes + SerMode = taurus.core.taurusbasetypes.TaurusSerializationMode m = options.taurus_serialization_mode.capitalize() - if hasattr(taurus.core.TaurusSerializationMode, m): - m = getattr(taurus.core.TaurusSerializationMode, m) + if hasattr(SerMode, m): + m = getattr(SerMode, m) taurus.Manager().setSerializationMode(m) - + + # initialize remote console port + if options.remote_console_port is not None: + try: + import rfoo.utils.rconsole + rfoo.utils.rconsole.spawn_server(port=options.remote_console_port) + taurus.info("rconsole started. You can connect to it by typing: rconsole -p %d", options.remote_console_port) + except Exception, e: + taurus.warning("Cannot spawn debugger. Reason: %s",str(e)) + return parser, options, args - \ No newline at end of file + +def split_taurus_args(parser, args=None): + """Splits arguments into valid parser arguments and non valid parser + arguments. + + :param parser: an option parser + :type parser: :class:`optparse.OptionParser` + :param args: the list of arguments to process + (default is None meaning: sys.argv) + :type args: seq + :return: a tuple of two elements: parser args, non parser args + :rtype: seq, seq>""" + + if args is None: + import sys + args = sys.argv + + taurus_args, non_taurus_args = [args[0]], [args[0]] + for arg in args[1:]: + arg_name = arg.split("=", 1)[0] + if parser.has_option(arg_name): + taurus_args.append(arg) + else: + non_taurus_args.append(arg) + + return taurus_args, non_taurus_args + diff -Nru taurus-3.0.0/lib/taurus/core/util/codecs.py taurus-3.1.0/lib/taurus/core/util/codecs.py --- taurus-3.0.0/lib/taurus/core/util/codecs.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/codecs.py 2013-07-25 07:53:43.000000000 +0000 @@ -38,7 +38,7 @@ Example:: - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> cf = CodecFactory() >>> json_codec = cf.getCodec('json') >>> bz2_json_codec = cf.getCodec('bz2_json') @@ -55,7 +55,7 @@ >>> # this example shows how to automatically get the data from a DEV_ENCODED attribute >>> import taurus - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> cf = CodecFactory() >>> devenc_attr = taurus.Attribute('a/b/c/devenc_attr') >>> v = devenc_attr.read() @@ -72,6 +72,10 @@ import operator import types +#need by VideoImageCodec +import struct +import numpy + from singleton import Singleton from log import Logger, DebugIt from containers import CaselessDict @@ -137,7 +141,7 @@ Example:: - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> # first encode something >>> data = 100 * "Hello world\\n" @@ -179,7 +183,7 @@ Example:: - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> # first encode something >>> data = 100 * "Hello world\\n" @@ -222,7 +226,7 @@ Example:: - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> cf = CodecFactory() >>> codec = cf.getCodec('pickle') @@ -277,7 +281,7 @@ Example:: - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> cf = CodecFactory() >>> codec = cf.getCodec('json') @@ -360,7 +364,7 @@ Example:: - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> cf = CodecFactory() >>> codec = cf.getCodec('bson') @@ -437,7 +441,9 @@ self._func_name = func_name def encode(self, data, *args, **kwargs): - return self._func_name, { 'type' : self._func_name, 'data' : data } + format = self._func_name + if len(data[0]): format += '_%s' % data[0] + return format, { 'type' : self._func_name, 'data' : data[1] } def decode(self, data, *args, **kwargs): if not data[0].startswith(self._func_name): @@ -452,12 +458,170 @@ FunctionCodec.__init__(self, 'plot') +class VideoImageCodec(Codec): + """A codec able to encode/decode to/from LImA video_image format. + + Example:: + + >>> from taurus.core.util.codecs import CodecFactory + >>> import PyTango + + >>> #first get an image from a LImA device to decode + >>> data = PyTango.DeviceProxy(ccdName).read_attribute('video_last_image').value + >>> cf = CodecFactory() + >>> codec = cf.getCodec('VIDEO_IMAGE') + >>> format,decoded_data = codec.decode(data) + >>> # encode it again to check + >>> format, encoded_data = codec.encode(("",decoded_data)) + >>> #compare images excluding the header: + >>> data[1][32:] == encoded_data[32:] + >>> #The headers can be different in the frameNumber + >>> struct.unpack('!IHHqiiHHHH',data[1][:32]) + (1447314767, 1, 0, 6868, 1294, 964, 0, 32, 0, 0) + >>> struct.unpack('!IHHqiiHHHH',encoded_data[:32]) + (1447314767, 1, 0, -1, 1294, 964, 0, 32, 0, 0) + """ + + VIDEO_HEADER_FORMAT = '!IHHqiiHHHH' + + def encode(self, data, *args, **kwargs): + """encodes the given data to a LImA's video_image. The given data **must** be an numpy.array + + :param data: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object + + :return: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object""" + + format = 'VIDEO_IMAGE' + if len(data[0]): format += '_%s' % data[0] + #imgMode depends on numpy.array dtype + imgMode = self.__getModeId(str(data[1].dtype)) + #frameNumber, unknown then -1 + height,width = data[1].shape + header = self.__packHeader(imgMode,-1,width,height) + img2D = data[1] + img1D = img2D.flatten() + buffer = struct.pack(self.__getFormatId(imgMode)*img1D.size,*img1D) + return format,header+buffer + + def decode(self, data, *args, **kwargs): + """decodes the given data from a LImA's video_image. + + :param data: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object + + :return: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object""" + + if not data[0] == 'VIDEO_IMAGE': + return data + header = self.__unpackHeader(data[1][:struct.calcsize(self.VIDEO_HEADER_FORMAT)]) + + imgBuffer = data[1][struct.calcsize(self.VIDEO_HEADER_FORMAT):] + fmt = self.__getFormatId(header['imageMode']) + img1D = numpy.array(struct.unpack(fmt*(len(imgBuffer)/struct.calcsize(fmt)), + imgBuffer), + dtype=self.__getDtypeId(header['imageMode'])) + img2D = img1D.reshape(header['height'],header['width']) + return '',img2D + + def __unpackHeader(self,header): + h = struct.unpack(self.VIDEO_HEADER_FORMAT,header) + headerDict={} + headerDict['magic'] = h[0] + headerDict['headerVersion'] = h[1] + headerDict['imageMode'] = h[2] + headerDict['frameNumber'] = h[3] + headerDict['width'] = h[4] + headerDict['height'] = h[5] + headerDict['endianness'] = h[6] + headerDict['headerSize'] = h[7] + headerDict['padding'] = h[7:] + return headerDict + + def __packHeader(self,imgMode,frameNumber,width,height): + magic = 0x5644454f + version = 1 + endian = ord(struct.pack('=H',1)[-1]) + hsize = struct.calcsize(self.VIDEO_HEADER_FORMAT) + return struct.pack(self.VIDEO_HEADER_FORMAT, + magic, + version, + imgMode, + frameNumber, + width, + height, + endian, + hsize, + 0,0)#padding + + def __getModeId(self,mode): + return {#when encode + 'uint8' : 0,#Core.Y8, + 'uint16' : 1,#Core.Y16, + 'uint32' : 2,#Core.Y32, + 'uint64' : 3,#Core.Y64, + #when decode + 'Y8' : 0,#Core.Y8, + 'Y16' : 1,#Core.Y16, + 'Y32' : 2,#Core.Y32, + 'Y64' : 3,#Core.Y64, + #TODO: other modes + #'RGB555' : Core.RGB555, + #'RGB565' : Core.RGB565, + #'RGB24' : Core.RGB24, + #'RGB32' : Core.RGB32, + #'BGR24' : Core.BGR24, + #'BGR32' : Core.BGR32, + #'BAYER RG8' : Core.BAYER_RG8, + #'BAYER RG16' : Core.BAYER_RG16, + #'I420' : Core.I420, + #'YUV411' : Core.YUV411, + #'YUV422' : Core.YUV422, + #'YUV444' : Core.YUV444 + }[mode] + + def __getFormatId(self,mode): + return {0 : 'B', + 1 : 'H', + 2 : 'I', + 3 : 'L', + #'RGB555' : Core.RGB555, + #'RGB565' : Core.RGB565, + #'RGB24' : Core.RGB24, + #'RGB32' : Core.RGB32, + #'BGR24' : Core.BGR24, + #'BGR32' : Core.BGR32, + #'BAYER RG8' : Core.BAYER_RG8, + #'BAYER RG16' : Core.BAYER_RG16, + #'I420' : Core.I420, + #'YUV411' : Core.YUV411, + #'YUV422' : Core.YUV422, + #'YUV444' : Core.YUV444 + }[mode] + + def __getDtypeId(self,mode): + return {0 : 'uint8', + 1 : 'uint16', + 2 : 'uint32', + 3 : 'uint64', + #'RGB555' : Core.RGB555, + #'RGB565' : Core.RGB565, + #'RGB24' : Core.RGB24, + #'RGB32' : Core.RGB32, + #'BGR24' : Core.BGR24, + #'BGR32' : Core.BGR32, + #'BAYER RG8' : Core.BAYER_RG8, + #'BAYER RG16' : Core.BAYER_RG16, + #'I420' : Core.I420, + #'YUV411' : Core.YUV411, + #'YUV422' : Core.YUV422, + #'YUV444' : Core.YUV444 + }[mode] + class CodecPipeline(Codec, list): """The codec class used when encoding/decoding data with multiple encoders Example usage:: - >>> from taurus.core.util import CodecPipeline + >>> from taurus.core.util.codecs import CodecPipeline >>> data = range(100000) >>> codec = CodecPipeline('bz2_json') @@ -512,7 +676,7 @@ To get the singleton object do:: - from taurus.core.util import CodecFactory + from taurus.core.util.codecs import CodecFactory f = CodecFactory() The :class:`CodecFactory` class allows you to get a codec object for a given @@ -522,7 +686,7 @@ Example:: - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> cf = CodecFactory() >>> json_codec = cf.getCodec('json') >>> bz2_json_codec = cf.getCodec('bz2_json') @@ -539,7 +703,7 @@ >>> # this example shows how to automatically get the data from a DEV_ENCODED attribute >>> import taurus - >>> from taurus.core.util import CodecFactory + >>> from taurus.core.util.codecs import CodecFactory >>> cf = CodecFactory() >>> devenc_attr = taurus.Attribute('a/b/c/devenc_attr') >>> v = devenc_attr.read() @@ -555,6 +719,7 @@ 'zip' : ZIPCodec, 'pickle' : PickleCodec, 'plot' : PlotCodec, + 'VIDEO_IMAGE' : VideoImageCodec, 'null' : NullCodec, 'none' : NullCodec, '' : NullCodec }) @@ -632,4 +797,4 @@ def encode(self, format, data, *args, **kwargs): return self.getCodec(format).encode(data, *args, **kwargs) - \ No newline at end of file + diff -Nru taurus-3.0.0/lib/taurus/core/util/console.py taurus-3.1.0/lib/taurus/core/util/console.py --- taurus-3.0.0/lib/taurus/core/util/console.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/console.py 2013-07-25 07:53:43.000000000 +0000 @@ -121,7 +121,7 @@ PyTango.DevState.UNKNOWN : HTMLColors.LightGray, None : HTMLColors.DarkGray } -from taurus.core import TaurusSWDevState +from taurus.core.taurusbasetypes import TaurusSWDevState NoTaurusSWDevStateColors = { TaurusSWDevState.Uninitialized : NoColors.LightGray, diff -Nru taurus-3.0.0/lib/taurus/core/util/containers.py taurus-3.1.0/lib/taurus/core/util/containers.py --- taurus-3.0.0/lib/taurus/core/util/containers.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/containers.py 2013-07-25 07:53:43.000000000 +0000 @@ -809,6 +809,79 @@ itervalues = self_locked(dict.itervalues) iteritems = self_locked(dict.iteritems) +class SortedDict(dict): + """ This class implements a dictionary that returns keys in the same order they were inserted. """ + + def __init__(self,other=None): + dict.__init__(self) + self._keys = [] + if other is not None: + self.update(other) + return + + def sort(self,key): + """ + This method modifies the sorting of the dictionary overriding the existing sort key. + :param key: it can be a sequence containing all the keys already existing in the dictionary + or a callable providing a sorting key algorithm. + """ + import operator + if operator.isCallable(key): + self._keys = sorted(self._keys,key=key) + else: + for k in self._keys: + if k not in self._keys: raise KeyError(k) + self._keys = list(key) + return self._keys[:] + + def __setitem__(self,k,v): + if k not in self._keys: + self._keys.append(k) + dict.__setitem__(self,k,v) + + def update(self,other): + if hasattr(other,'items'): + other = other.items() + for k,v in other: + self.__setitem__(k,v) + + @staticmethod + def fromkeys(S,v=None): + return SortedDict((s,v) for s in S) + + def pop(self,k,d=None): + """Removes key and returns its (self[key] or d or None)""" + if k not in self: return d + self._keys.remove(k) + return dict.pop(self,k) + + def popitem(self): + """Removes and returns last key,value pair""" + k = self._keys[-1] + v = self[k] + self.pop(k) + return k,v + + def clear(self): + self._keys = [] + return dict.clear(self) + + def keys(self): + return self._keys[:] + def values(self): + return [self[k] for k in self._keys] + def items(self): + return [(k,self[k]) for k in self._keys] + + def __iter__(self): + return (i for i in self._keys) + def iteritems(self): + return ((k,self[k]) for k in self._keys) + def iterkeys(self): + return (i for i in self._keys) + def itervalues(self): + return (self[k] for k in self._keys) + try: from collections import defaultdict except: @@ -847,7 +920,6 @@ return 'defaultdict(%s, %s)' % (self.default_factory, dict.__repr__(self)) - class defaultdict_fromkey(defaultdict): """ Creates a dictionary with a default_factory function that creates new elements using key as argument. Usage : new_dict = defaultdict_fromkey(method); where method like (lambda key: return new_obj(key)) diff -Nru taurus-3.0.0/lib/taurus/core/util/decorator/memoize.py taurus-3.1.0/lib/taurus/core/util/decorator/memoize.py --- taurus-3.0.0/lib/taurus/core/util/decorator/memoize.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/decorator/memoize.py 2013-07-25 07:53:42.000000000 +0000 @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +import functools + + +class memoized(object): + '''Decorator. Caches a function's return value each time it is called. + If called later with the same arguments, the cached value is returned + (not reevaluated). + ''' + + def __init__(self, func): + self.func = func + self.cache = {} + + def __call__(self, *args): + try: + return self.cache[args] + except KeyError: + value = self.func(*args) + self.cache[args] = value + return value + except TypeError: + # uncachable -- for instance, passing a list as an argument. + # Better to not cache than to blow up entirely. + return self.func(*args) + + def __repr__(self): + '''Return the function's docstring.''' + return self.func.__doc__ + + def __get__(self, obj, objtype): + '''Support instance methods.''' + return functools.partial(self.__call__, obj) diff -Nru taurus-3.0.0/lib/taurus/core/util/enumeration.py taurus-3.1.0/lib/taurus/core/util/enumeration.py --- taurus-3.0.0/lib/taurus/core/util/enumeration.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/enumeration.py 2013-07-25 07:53:43.000000000 +0000 @@ -51,7 +51,7 @@ as elements of a dictionary. Usage:: - from taurus.core.util import Enumeration + from taurus.core.util.enumeration import Enumeration Volkswagen = Enumeration("Volkswagen", ["JETTA", diff -Nru taurus-3.0.0/lib/taurus/core/util/event.py taurus-3.1.0/lib/taurus/core/util/event.py --- taurus-3.0.0/lib/taurus/core/util/event.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/event.py 2013-07-25 07:53:43.000000000 +0000 @@ -381,7 +381,7 @@ with this object's lock before calling this method and always unlock it afterward, of course:: - from taurus.core.util import EventListener + from taurus.core.util.event import EventListener class MyEvtListener(EventListener): # Your specific listener code here @@ -460,7 +460,7 @@ class AttributeEventWait(object): - """Class designed to connect to a :class:`taurus.core.TaurusAttribute` and + """Class designed to connect to a :class:`taurus.core.taurusattribute.TaurusAttribute` and fire events or wait for a certain event.""" def __init__(self, attr=None): @@ -474,7 +474,7 @@ def connect(self, attr): """Connect to the given attribute :param attr: the attribute to connect to - :type attr: taurus.core.TaurusAttribute""" + :type attr: taurus.core.taurusattribute.TaurusAttribute""" needAdd = True if self._attr is not None: if attr == self._attr: @@ -521,9 +521,9 @@ """Event listener method for the underlying attribute. Do not call this method. It will be called internally when the attribute generates an event.""" - if t == taurus.core.TaurusEventType.Config: + if t == taurus.core.taurusbasetypes.TaurusEventType.Config: return - elif t == taurus.core.TaurusEventType.Error: + elif t == taurus.core.taurusbasetypes.TaurusEventType.Error: self.fireEvent(None) else: self.fireEvent(v.value) @@ -662,7 +662,7 @@ "locked by thread %s" % (curr_th.name, th.name) def eventReceived(self, s, t, v): - if t not in (taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic): + if t not in (taurus.core.taurusbasetypes.TaurusEventType.Change, taurus.core.taurusbasetypes.TaurusEventType.Periodic): return self.fireEvent(s, v.value) diff -Nru taurus-3.0.0/lib/taurus/core/util/eventfilters.py taurus-3.1.0/lib/taurus/core/util/eventfilters.py --- taurus-3.0.0/lib/taurus/core/util/eventfilters.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/eventfilters.py 2013-07-25 07:53:43.000000000 +0000 @@ -34,32 +34,32 @@ def ONLY_CHANGE(s, t, v): '''Only change events pass''' - if t == taurus.core.TaurusEventType.Change: return s,t,v + if t == taurus.core.taurusbasetypes.TaurusEventType.Change: return s,t,v else: return None def IGNORE_CHANGE(s, t, v): '''Config events are discarded''' - if t != taurus.core.TaurusEventType.Change: return s,t,v + if t != taurus.core.taurusbasetypes.TaurusEventType.Change: return s,t,v else: return None def ONLY_CHANGE_AND_PERIODIC(s, t, v): '''Only change events pass''' - if t in [taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic]: return s,t,v + if t in [taurus.core.taurusbasetypes.TaurusEventType.Change, taurus.core.taurusbasetypes.TaurusEventType.Periodic]: return s,t,v else: return None def IGNORE_CHANGE_AND_PERIODIC(s, t, v): '''Config events are discarded''' - if t not in [taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic]: return s,t,v + if t not in [taurus.core.taurusbasetypes.TaurusEventType.Change, taurus.core.taurusbasetypes.TaurusEventType.Periodic]: return s,t,v else: return None def ONLY_CONFIG(s, t, v): '''Only config events pass''' - if t == taurus.core.TaurusEventType.Config: return s,t,v + if t == taurus.core.taurusbasetypes.TaurusEventType.Config: return s,t,v else: return None def IGNORE_CONFIG(s, t, v): '''Config events are discarded''' - if t != taurus.core.TaurusEventType.Config: return s,t,v + if t != taurus.core.taurusbasetypes.TaurusEventType.Config: return s,t,v else: return None def ONLY_VALID(s, t, v): @@ -95,7 +95,7 @@ } def __call__(self, s, t, v): - if not t in (taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic): + if not t in (taurus.core.taurusbasetypes.TaurusEventType.Change, taurus.core.taurusbasetypes.TaurusEventType.Periodic): return s, t, v if v is None: return s, t, v diff -Nru taurus-3.0.0/lib/taurus/core/util/init_bkcomp.py taurus-3.1.0/lib/taurus/core/util/init_bkcomp.py --- taurus-3.0.0/lib/taurus/core/util/init_bkcomp.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/init_bkcomp.py 2013-07-25 07:53:43.000000000 +0000 @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""This package consists of a collection of useful classes and functions. Most of +the elements are taurus independent and can be used generically. + +This module contains a python implementation of :mod:`json`. This was done because +json only became part of python since version 2.6. +The json implementation follows the rule: + + #. if python >= 2.6 use standard json from python distribution + #. otherwise use private implementation distributed with taurus +""" + +__docformat__ = "restructuredtext" + +# taurus cannot work properly without the following modules so +# they are promptly imported here has a facility (also for backward +# compatibility) +# However, new applications should in their code use the full import. +# Example, use: +# from taurus.core.util.log import Logger +# instead of: +# from taurus.core.util import Logger + +from .containers import * +from .enumeration import * +from .event import * +from .log import * +from .object import * +from .singleton import * + +from .codecs import * +from .colors import * +from .constant import * +from .timer import * +from .safeeval import * +from .prop import * +from .threadpool import * +from .user import * + +import eventfilters + +try: + from lxml import etree +except: + etree = None + +def dictFromSequence(seq): + """Translates a sequence into a dictionary by converting each to elements of + the sequence (k,v) into a k:v pair in the dictionary + + :param seq: (sequence) any sequence object + :return: (dict) dictionary built from the given sequence""" + def _pairwise(iterable): + """Utility method used by dictFromSequence""" + itnext = iter(iterable).next + while True: + yield itnext(), itnext() + return dict(_pairwise(seq)) diff -Nru taurus-3.0.0/lib/taurus/core/util/init_lightweight.py taurus-3.1.0/lib/taurus/core/util/init_lightweight.py --- taurus-3.0.0/lib/taurus/core/util/init_lightweight.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/init_lightweight.py 2013-07-25 07:53:43.000000000 +0000 @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""This package consists of a collection of useful classes and functions. Most of +the elements are taurus independent and can be used generically. + +This module contains a python implementation of :mod:`json`. This was done because +json only became part of python since version 2.6. +The json implementation follows the rule: + + #. if python >= 2.6 use standard json from python distribution + #. otherwise use private implementation distributed with taurus +""" + +__docformat__ = "restructuredtext" + +# taurus cannot work properly without the following modules so +# they are promptly imported here has a facility (also for backward +# compatibility) +# However, new applications should in their code use the full import. +# Example, use: +# from taurus.core.util.log import Logger +# instead of: +# from taurus.core.util import Logger + +from .containers import * +from .enumeration import * +from .event import * +from .log import * +from .object import * +from .singleton import * + +# from .codecs import * +# from .colors import * +# from .constant import * +# from .timer import * +# from .safeeval import * +# from .prop import * +# from .threadpool import * +# from .user import * + +# import eventfilters + +# try: + # from lxml import etree +# except: + # etree = None + +def dictFromSequence(seq): + """Translates a sequence into a dictionary by converting each to elements of + the sequence (k,v) into a k:v pair in the dictionary + + :param seq: (sequence) any sequence object + :return: (dict) dictionary built from the given sequence""" + def _pairwise(iterable): + """Utility method used by dictFromSequence""" + itnext = iter(iterable).next + while True: + yield itnext(), itnext() + return dict(_pairwise(seq)) diff -Nru taurus-3.0.0/lib/taurus/core/util/log.py taurus-3.1.0/lib/taurus/core/util/log.py --- taurus-3.0.0/lib/taurus/core/util/log.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/log.py 2013-07-25 07:53:43.000000000 +0000 @@ -3,32 +3,33 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## ############################################################################# -"""This module contains a set of useful logging elements based on python's +"""This module contains a set of useful logging elements based on python's :mod:`logging` system.""" __all__ = ["LogIt", "TraceIt", "DebugIt", "InfoIt", "WarnIt", "ErrorIt", "CriticalIt", "MemoryLogHandler", "LogExceptHook", "Logger", - "LogFilter"] + "LogFilter", + "_log", "trace", "debug", "info", "warning", "error", "critical"] __docformat__ = "restructuredtext" @@ -39,77 +40,101 @@ import warnings import traceback import inspect -import functools import threading from object import Object +from wrap import wraps from excepthook import BaseExceptHook TRACE = 5 logging.addLevelName(TRACE, "TRACE") +# +# _srcfile is used when walking the stack to check when we've got the first +# caller stack frame. +# +if hasattr(sys, 'frozen'): #support for py2exe + _srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:]) +elif __file__[-4:].lower() in ['.pyc', '.pyo']: + _srcfile = __file__[:-4] + '.py' +else: + _srcfile = __file__ +_srcfile = os.path.normcase(_srcfile) + +# next bit filched from 1.5.2's inspect.py +def currentframe(): + """Return the frame object for the caller's stack frame.""" + try: + raise Exception + except: + return sys.exc_info()[2].tb_frame.f_back + +if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3) +# done filching + + class LogIt(object): """A function designed to be a decorator of any method of a Logger subclass. The idea is to log the entrance and exit of any decorated method of a Logger subclass. Example:: - - from taurus.core.util import * - + + from taurus.core.util.log import Logger, LogIt + class Example(Logger): - + @LogIt(Logger.Debug) def go(self): print "Hello world " - + This will generate two log messages of Debug level, one before the function go is called and another when go finishes. Example output:: - + MainThread DEBUG 2010-11-15 15:36:11,440 Example: -> go Hello world of mine MainThread DEBUG 2010-11-15 15:36:11,441 Example: <- go - + This decorator can receive two optional arguments **showargs** and **showret** which are set to False by default. Enabling them will had verbose infomation about the parameters and return value. The following example:: - from taurus.core.util import * - + from taurus.core.uti.log import Logger, LogIt + class Example(Logger): - + @LogIt(Logger.Debug, showargs=True, showret=True) def go(self, msg): msg = "Hello world",msg print msg return msg - + would generate an output like:: MainThread DEBUG 2010-11-15 15:42:02,353 Example: -> go('of mine',) Hello world of mine MainThread DEBUG 2010-11-15 15:42:02,353 Example: <- go = Hello world of mine - - .. note:: + + .. note:: it may happen that in these examples that the output of the method appears before or after the log messages. This is because log messages are, by default, written to the *stardard error* while the print message inside the go method outputs to the *standard ouput*. On many systems these two targets are not synchronized. """ - + def __init__(self, level=logging.DEBUG, showargs=False, showret=False, col_limit=0): self._level = level self._showargs = showargs self._showret = showret self._col_limit = col_limit - + def __call__(self, f): - @functools.wraps(f) + @wraps(f) def wrapper(*args, **kwargs): f_self = args[0] if f_self.log_level > self._level: return f(*args, **kwargs) - + has_log = hasattr(f_self, "log") fname = f.func_name log_obj = f_self @@ -146,14 +171,14 @@ class TraceIt(LogIt): """Specialization of LogIt for trace level messages. Example:: - - from taurus.core.util import TraceIt + + from taurus.core.util.log import Logger, TraceIt class Example(Logger): - + @TraceIt() def go(self): print "Hello world" - + .. seealso:: :class:`LogIt`""" def __init__(self, showargs=False, showret=False): LogIt.__init__(self, level=TRACE, showargs=showargs, showret=showret) @@ -162,14 +187,14 @@ class DebugIt(LogIt): """Specialization of LogIt for debug level messages. Example:: - - from taurus.core.util import DebugIt + + from taurus.core.util.log import Logger, DebugIt class Example(Logger): - + @DebugIt() def go(self): print "Hello world" - + .. seealso:: :class:`LogIt`""" def __init__(self, showargs=False, showret=False): LogIt.__init__(self, level=logging.DEBUG, showargs=showargs, showret=showret) @@ -178,14 +203,14 @@ class InfoIt(LogIt): """Specialization of LogIt for info level messages. Example:: - - from taurus.core.util import InfoIt + + from taurus.core.util.log import Logger, InfoIt class Example(Logger): - + @InfoIt() def go(self): print "Hello world" - + .. seealso:: :class:`LogIt`""" def __init__(self, showargs=False, showret=False): LogIt.__init__(self, level=logging.INFO, showargs=showargs, showret=showret) @@ -194,14 +219,14 @@ class WarnIt(LogIt): """Specialization of LogIt for warn level messages. Example:: - - from taurus.core.util import WarnIt + + from taurus.core.util.log import Logger, WarnIt class Example(Logger): - + @WarnIt() def go(self): print "Hello world" - + .. seealso:: :class:`LogIt`""" def __init__(self, showargs=False, showret=False): LogIt.__init__(self, level=logging.WARN, showargs=showargs, showret=showret) @@ -210,14 +235,14 @@ class ErrorIt(LogIt): """Specialization of LogIt for error level messages. Example:: - - from taurus.core.util import ErrorIt + + from taurus.core.util.log import Logger, ErrorIt class Example(Logger): - + @ErrorIt() def go(self): print "Hello world" - + .. seealso:: :class:`LogIt`""" def __init__(self, showargs=False, showret=False): LogIt.__init__(self, level=logging.ERROR, showargs=showargs, showret=showret) @@ -226,14 +251,14 @@ class CriticalIt(LogIt): """Specialization of LogIt for critical level messages. Example:: - - from taurus.core.util import CriticalIt + + from taurus.core.util.log import Logger, CriticalIt class Example(Logger): - + @CriticalIt() def go(self): print "Hello world" - + .. seealso:: :class:`LogIt`""" def __init__(self, showargs=False, showret=False): LogIt.__init__(self, level=logging.CRITICAL, showargs=showargs, showret=showret) @@ -242,22 +267,22 @@ class MemoryLogHandler(list, logging.handlers.BufferingHandler): """An experimental log handler that stores temporary records in memory. When flushed it passes the records to another handler""" - + def __init__(self, capacity=1000): list.__init__(self) logging.handlers.BufferingHandler.__init__(self, capacity=capacity) self._handler_list_changed = False - + def shouldFlush(self, record): """Determines if the given record should trigger the flush - + :param record: (logging.LogRecord) a log record :return: (bool) wheter or not the handler should be flushed """ return (len(self.buffer) >= self.capacity) or \ (record.levelno >= Logger.getLogLevel()) or \ self._handler_list_changed - + def flush(self): """Flushes this handler""" for record in self.buffer: @@ -269,13 +294,13 @@ """Closes this handler""" self.flush() del self[:] - BufferingHandler.close(self) + logging.handlers.BufferingHandler.close(self) class LogExceptHook(BaseExceptHook): """A callable class that acts as an excepthook that logs the exception in the python logging system. - + :param hook_to: callable excepthook that will be called at the end of this hook handling [default: None] :type hook_to: callable @@ -283,13 +308,13 @@ :type name: str :param level: log level [default: logging.ERROR] :type level: int""" - + def __init__(self, hook_to=None, name=None, level=logging.ERROR): BaseExceptHook.__init__(self, hook_to=hook_to) name = name or self.__class__.__name__ self._level = level self._log = Logger(name=name) - + def report(self, *exc_info): text = "".join(traceback.format_exception(*exc_info)) if text[-1] == '\n': @@ -297,63 +322,90 @@ self._log.log(self._level, "Unhandled exception:\n%s", text) +class _Logger(logging.Logger): + + def findCaller(self): + """ + Find the stack frame of the caller so that we can note the source + file name, line number and function name. + """ + f = currentframe() + #On some versions of IronPython, currentframe() returns None if + #IronPython isn't run with -X:Frames. + if f is not None: + f = f.f_back + rv = "(unknown file)", 0, "(unknown function)" + while hasattr(f, "f_code"): + co = f.f_code + filename = os.path.normcase(co.co_filename) + if filename in (_srcfile, logging._srcfile): + f = f.f_back + continue + rv = (co.co_filename, f.f_lineno, co.co_name) + break + return rv + + class Logger(Object): """The taurus logger class. All taurus pertinent classes should inherit directly or indirectly from this class if they need taurus logging facilities.""" - + #: Internal usage root_inited = False - + #: Internal usage root_init_lock = threading.Lock() - + #: Critical message level (constant) Critical = logging.CRITICAL - + #: Error message level (constant) Error = logging.ERROR - + #: Warning message level (constant) Warning = logging.WARNING - + #: Info message level (constant) Info = logging.INFO - + #: Debug message level (constant) Debug = logging.DEBUG - + #: Trace message level (constant) Trace = TRACE - + #: Default log level (constant) DftLogLevel = Info - + + #: Default log message format (constant) + DftLogMessageFormat = '%(threadName)-14s %(levelname)-8s %(asctime)s %(name)s: %(message)s' + #: Default log format (constant) - DftLogFormat = logging.Formatter('%(threadName)-14s %(levelname)-8s %(asctime)s %(name)s: %(message)s') - + DftLogFormat = logging.Formatter(DftLogMessageFormat) + #: Current global log level log_level = DftLogLevel - + #: Default log message format log_format = DftLogFormat - + #: the main stream handler stream_handler = None - - + + def __init__(self, name='', parent=None, format=None): """The Logger constructor - + :param name: (str) the logger name (default is empty string) :param parent: (Logger) the parent logger or None if no parent exists (default is None) :param format: (str) the log message format or None to use the default log format (default is None) """ self.call__init__(Object) - + if format: self.log_format = format Logger.initRoot() - + if name is None or len(name) == 0: name = self.__class__.__name__ self.log_name = name @@ -361,8 +413,8 @@ self.log_full_name = '%s.%s' % (parent.log_full_name, name) else: self.log_full_name = name - - self.log_obj = logging.getLogger(self.log_full_name) + + self.log_obj = self._getLogger(self.log_full_name) self.log_handlers = [] self.log_parent = None @@ -373,8 +425,7 @@ def cleanUp(self): """The cleanUp. Default implementation does nothing - Overwrite when necessary - """ + Overwrite when necessary""" pass @classmethod @@ -383,16 +434,16 @@ method directly in your code """ if cls.root_inited: - return cls._getRootLog() - + return cls._getLogger() + try: cls.root_init_lock.acquire() - root_logger = cls._getRootLog() + root_logger = cls._getLogger() logging.addLevelName(cls.Trace, "TRACE") cls.stream_handler = logging.StreamHandler(sys.__stderr__) cls.stream_handler.setFormatter(cls.log_format) root_logger.addHandler(cls.stream_handler) - + console_log_level = os.environ.get("TAURUSLOGLEVEL", None) if console_log_level is not None: console_log_level = console_log_level.capitalize() @@ -407,16 +458,16 @@ @classmethod def addRootLogHandler(cls, h): """Adds a new handler to the root logger - + :param h: (logging.Handler) the new log handler """ h.setFormatter(cls.getLogFormat()) cls.initRoot().addHandler(h) - + @classmethod def removeRootLogHandler(cls, h): """Removes the given handler from the root logger - + :param h: (logging.Handler) the handler to be removed """ cls.initRoot().removeHandler(h) @@ -438,24 +489,24 @@ @classmethod def setLogLevel(cls,level): """sets the new log level (the root log level) - + :param level: (int) the new log level """ cls.log_level = level cls.initRoot().setLevel(level) - + @classmethod def getLogLevel(cls): """Retuns the current log level (the root log level) - + :return: (int) a number representing the log level """ return cls.log_level - + @classmethod def setLogFormat(cls,format): """sets the new log message format - + :param level: (str) the new log message format """ cls.log_format = logging.Formatter(format) @@ -466,11 +517,11 @@ @classmethod def getLogFormat(cls): """Retuns the current log message format (the root log format) - + :return: (str) the log message format """ return cls.log_format - + @classmethod def resetLogLevel(cls): """Resets the log level (the root log level)""" @@ -480,11 +531,11 @@ def resetLogFormat(cls): """Resets the log message format (the root log format)""" cls.setLogFormat(cls.DftLogFormat) - + @classmethod def addLevelName(cls, level_no, level_name): """Registers a new log level - + :param level_no: (int) the level number :param level_name: (str) the corresponding name """ @@ -492,30 +543,40 @@ level_name = level_name.capitalize() if not hasattr(cls, level_name): setattr(cls, level_name, level_no) - + @classmethod def getRootLog(cls): """Retuns the root logger - + :return: (logging.Logger) the root logger """ - cls.initRoot() - return cls._getRootLog() + return cls.initRoot() + + @staticmethod + def _getLogger(name=None): + orig_logger_class = logging.getLoggerClass() + try: + logging.setLoggerClass(_Logger) + ret = logging.getLogger(name) + return ret + finally: + logging.setLoggerClass(orig_logger_class) @classmethod - def _getRootLog(cls): - return logging.getLogger() - + def getLogger(cls, name=None): + cls.initRoot() + return cls._getLogger(name=name) + def getLogObj(self): """Returns the log object for this object - + :return: (logging.Logger) the log object """ return self.log_obj - + def getParent(self): """Returns the log parent for this object or None if no parent exists - + :return: (logging.Logger or None) the log parent for this object """ if self.log_parent is None: @@ -524,7 +585,7 @@ def getChildren(self): """Returns the log children for this object - + :return: (sequence. +## +############################################################################# + +"""Useful module for remote logging""" + +from __future__ import print_function +from __future__ import with_statement + +__all__ = ["LogRecordStreamHandler", "LogRecordSocketReceiver", "log"] + +import time +import socket +import pickle +import logging +import logging.handlers +import struct +import weakref + +try: + import socketserver +except: + import SocketServer as socketserver + + +class LogRecordStreamHandler(socketserver.StreamRequestHandler): + + def handle(self): + try: + return self._handle() + except: + pass + + def _handle(self): + self._stop = stop = 0 + self.hostName = self.server.hostName + self.server.registerHandler(self) + while not stop: + chunk = self.connection.recv(4) + if len(chunk) < 4: + break + slen = struct.unpack('>L', chunk)[0] + chunk = self.connection.recv(slen) + while len(chunk) < slen: + chunk = chunk + self.connection.recv(slen - len(chunk)) + obj = self.unPickle(chunk) + record = self.makeLogRecord(obj) + self.handleLogRecord(record) + stop = self._stop + + def unPickle(self, data): + return pickle.loads(data) + + def makeLogRecord(self, obj): + record = logging.makeLogRecord(obj) + if not hasattr(record, 'hostName'): + record.hostName = self.hostName + return record + + def handleLogRecord(self, record): + logger = self.server.data.get("logger") + if logger is None: + logger = logging.getLogger(record.name) + if not logger.isEnabledFor(record.levelno): + return + logger.handle(record) + + def stop(self): + self._stop = 1 + + +class LogRecordSocketReceiver(socketserver.ThreadingTCPServer): + """ + Simple TCP socket-based logging receiver suitable for testing. + """ + + allow_reuse_address = 1 + daemon_threads = True + + def __init__(self, host='localhost', + port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, + handler=LogRecordStreamHandler, **kwargs): + socketserver.ThreadingTCPServer.__init__(self, (host, port), handler) + self.hostName = socket.gethostbyaddr(host)[0] + self.port = port + self._stop = 0 + self._stopped = 0 + self.timeout = 1 + self.data = kwargs + self.__handlers = [] + + def registerHandler(self, handler): + if handler is not None: + self.__handlers.append(weakref.ref(handler)) + + def unregisterHandler(self, handler): + try: + self.__handlers.remove(handler) + except ValueError: + pass + + def serve_until_stopped(self): + import select + stop = 0 + while not stop: + rd, wr, ex = select.select([self.socket.fileno()], + [], [], + self.timeout) + if rd: + self.handle_request() + stop = self._stop + self._stopped = 1 + + def stop(self): + self._stop = True + while not self._stopped: + time.sleep(0.1) + for handler in self.__handlers: + h = handler() + if h is not None: + h.stop() + h.finish() + self.close_request(h.connection) + self.socket.close() + + +class LogNameFilter(logging.Filter): + + def __init__(self, name=None): + self.name = name + + def filter(self, record): + name = self.name + if name is None: + return True + return record.name == name + + +def log(host, port, name=None, level=None): + local_logger_name = "RemoteLogger.%s.%d" % (host, port) + local_logger = logging.getLogger(local_logger_name) + + if name is not None: + local_logger.addFilter(LogNameFilter(name=name)) + + if level is not None: + local_logger.setLevel(level) + + tcpserver = LogRecordSocketReceiver(host=host, port=port, + logger=local_logger) + msg = "logging for '%s' on port %d" % (host, port) + if name is not None: + msg += " for " + name + print("Start", msg) + + try: + tcpserver.serve_until_stopped() + except KeyboardInterrupt: + print("\nCancelled", msg) + + +def main(argv=None): + import optparse + import socket + + import taurus.core.util.log + + taurus.setLogLevel(taurus.Trace) + + dft_port = logging.handlers.DEFAULT_TCP_LOGGING_PORT + + host = socket.gethostname() + + help_port = "port where log server is running [default: %d]" % dft_port + help_name = "filter specific log object [default: None, meaning don't " \ + "filter]" + help_level = "filter specific log level." \ + "Allowed values are (case insensitive): critical, "\ + "error, warning/warn, info, debug, trace [default: debug]." + + parser = optparse.OptionParser() + parser.add_option("--log-port", dest="log_port", default=dft_port, + type="int", help=help_port) + parser.add_option("--log-name", dest="log_name", default=None, + type="string", help=help_name) + parser.add_option("--log-level", dest="log_level", default="debug", + type="string", help=help_level) + + if argv is None: + import sys + argv = sys.argv + + options, args = parser.parse_args(args=argv) + + port, name = options.log_port, options.log_name + level_str = options.log_level.capitalize() + + level = None + if hasattr(taurus, level_str): + level = getattr(taurus, level_str) + + log(host, port, name=name, level=level) + +if __name__ == '__main__': + main() diff -Nru taurus-3.0.0/lib/taurus/core/util/safeeval.py taurus-3.1.0/lib/taurus/core/util/safeeval.py --- taurus-3.0.0/lib/taurus/core/util/safeeval.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/safeeval.py 2013-07-25 07:53:43.000000000 +0000 @@ -47,10 +47,10 @@ Note: In order to use variables defined outside, the user must explicitly declare them safe. """ def __init__(self, safedict=None, defaultSafe=True): - self._default_numpy = ('abs', 'array', 'arange','arccos', 'arcsin', 'arctan', 'arctan2', + self._default_numpy = ('abs', 'array', 'arange','arccos', 'arcsin', 'arctan', 'arctan2', 'average', 'ceil', 'cos', 'cosh', 'degrees', 'dot', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'linspace', 'log', 'log10', 'logspace', - 'modf', 'ones', 'pi', 'radians', 'shape', 'sin', 'sinh', 'sqrt', 'tan', + 'modf', 'ones', 'pi', 'radians', 'shape', 'sin', 'sinh', 'sqrt', 'sum', 'tan', 'tanh','zeros') self._default_numpy_random = ('randn', 'rand', 'randint') diff -Nru taurus-3.0.0/lib/taurus/core/util/singleton.py taurus-3.1.0/lib/taurus/core/util/singleton.py --- taurus-3.0.0/lib/taurus/core/util/singleton.py 2012-04-30 07:47:17.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/singleton.py 2013-07-25 07:53:43.000000000 +0000 @@ -36,7 +36,7 @@ The Singleton is created for the lowest subclass. Usage:: - from taurus.core.util import Singleton + from taurus.core.util.singleton import Singleton class MyManager(Singleton): diff -Nru taurus-3.0.0/lib/taurus/core/util/wrap.py taurus-3.1.0/lib/taurus/core/util/wrap.py --- taurus-3.0.0/lib/taurus/core/util/wrap.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/core/util/wrap.py 2013-07-25 07:53:43.000000000 +0000 @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""""" + +__all__ = ["wraps", "wrapped", "is_wrapping", "is_wrapped"] + +import weakref +from functools import wraps as _wraps + +__WRAPPED = "__wrapped__" +__WRAPPER = "__wrapper__" + +def wraps(wrapped, *args, **kwargs): + """A wrap decorator which stores in the returned function a reference to + the wrapped function (in member '__wrapped__')""" + wrapper = _wraps(wrapped, *args, **kwargs) + setattr(wrapper, __WRAPPED, weakref.ref(wrapped)) + setattr(wrapped, __WRAPPER, weakref.ref(wrapper)) + return wrapper + +def is_wrapping(wrapper): + """Determines if the given callable is a wrapper for another callable""" + return hasattr(wrapper, __WRAPPED) + +def is_wrapped(wrapped): + """Determines if the given callable is being wrapped by another callable""" + return hasattr(wrapped, __WRAPPER) + +def wrapped(wrapper, recursive=True): + """Returns the wrapped function around the given wrapper. If the given + callable is not "wrapping" any function, the wrapper itself is returned""" + if is_wrapping(wrapper): + _wrapped = wrapper.__wrapped__() + else: + return wrapper + + if recursive: + return wrapped(_wrapped) + return _wrapped + + \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/qt/Qt.py taurus-3.1.0/lib/taurus/qt/Qt.py --- taurus-3.0.0/lib/taurus/qt/Qt.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/Qt.py 2013-07-25 07:53:41.000000000 +0000 @@ -27,9 +27,120 @@ from taurusqtoptions import QT_API, QT_API_PYQT, QT_API_PYSIDE +def __to_qvariant_1(pyobj=None): + """Properly converts a python object into a proper QVariant according to + the PySide or PyQt4 API version in use + + :param pyobj: object to be converted + :return: A proper QVariant""" + from PyQt4.QtCore import QVariant + if pyobj is None: + return QVariant() # PyQt 4.4 doesn't accept QVariant(None) + return QVariant(pyobj) + +def __from_qvariant_1(qobj=None, convfunc=None): + """Properly converts a QVariant/QVariant equivalent to a python object + according to the PySide or PyQt4 API version in use + + :param qobj: object to be converted + :param convfunc: + conversion function. Not used if QVariant is not available. + If QVariant is available: [default: None, meaning use + qobj.toPyObject()]. Can be a function like str, int, bool, float or + a string containing the conversion method (ex.: 'toByteArray') will + call qobj.toByteArray() + :return: A proper python object""" + if convfunc is None: + return qobj.toPyObject() + elif callable(convfunc): + if convfunc in (unicode, str): + return convfunc(qobj.toString()) + elif convfunc is bool: + return qobj.toBool() + elif convfunc is int: + return qobj.toInt()[0] + elif convfunc is float: + return qobj.toDouble()[0] + elif isinstance(convfunc, (str, unicode)): + return getattr(qobj, convfunc)() + +def __QVariant_2(pyobj=None): + return pyobj + +def __to_qvariant_2(pyobj=None): + """Properly converts a python object into a proper QVariant according to + the PySide or PyQt4 API version in use + + :param pyobj: object to be converted + :return: A proper QVariant""" + return pyobj + +def __from_qvariant_2(qobj=None, convfunc=None): + """Properly converts a QVariant/QVariant equivalent to a python object + according to the PySide or PyQt4 API version in use + + :param qobj: object to be converted + :param convfunc: + conversion function. Not used if QVariant is not available. + If QVariant is available: [default: None, meaning use + qobj.toPyObject()]. Can be a function like str, int, bool, float or + a string containing the conversion method (ex.: 'toByteArray') will + call qobj.toByteArray() + :return: A proper python object""" + return qobj + +#def __QString_2(pyobj=""): +# return str(pyobj) + +__QString_2 = str + +#def __QStringList_2(pyobj=None): +# if pyobj is None: +# return list() +# if isinstance(pyobj, (str, unicode)): +# return [pyobj] +# return list(pyobj) + +__QStringList_2 = list + # Now peform the imports. if QT_API == QT_API_PYQT: + import PyQt4.Qt + import PyQt4.QtCore from PyQt4.Qt import * from PyQt4.Qt import Qt + + import sip + try: + PYQT_QVARIANT_API_1 = sip.getapi('QVariant') == 1 + except AttributeError: + # PyQt . +## +############################################################################# + +"""This module exposes PyQt4.QtSvg module""" + +from taurusqtoptions import QT_API, QT_API_PYQT, QT_API_PYSIDE + +# Now peform the imports. +if QT_API == QT_API_PYQT: + from PyQt4.QtDesigner import * +elif QT_API == QT_API_PYSIDE: + from PySide.QtDesigner import * diff -Nru taurus-3.0.0/lib/taurus/qt/QtNetwork.py taurus-3.1.0/lib/taurus/qt/QtNetwork.py --- taurus-3.0.0/lib/taurus/qt/QtNetwork.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/QtNetwork.py 2013-07-25 07:53:41.000000000 +0000 @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""This module exposes PyQt4.QtGui module""" + +from taurusqtoptions import QT_API, QT_API_PYQT, QT_API_PYSIDE + +# Now peform the imports. +if QT_API == QT_API_PYQT: + from PyQt4.QtNetwork import * +elif QT_API == QT_API_PYSIDE: + from PySide.QtNetwork import * diff -Nru taurus-3.0.0/lib/taurus/qt/QtSvg.py taurus-3.1.0/lib/taurus/qt/QtSvg.py --- taurus-3.0.0/lib/taurus/qt/QtSvg.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/QtSvg.py 2013-07-25 07:53:41.000000000 +0000 @@ -3,21 +3,21 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## @@ -31,4 +31,4 @@ if QT_API == QT_API_PYQT: from PyQt4.QtSvg import * elif QT_API == QT_API_PYSIDE: - from PySide.QtSvg import * \ No newline at end of file + from PySide.QtSvg import * diff -Nru taurus-3.0.0/lib/taurus/qt/QtWebKit.py taurus-3.1.0/lib/taurus/qt/QtWebKit.py --- taurus-3.0.0/lib/taurus/qt/QtWebKit.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/QtWebKit.py 2013-07-25 07:53:41.000000000 +0000 @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""This module exposes PyQt4.QtGui module""" + +from taurusqtoptions import QT_API, QT_API_PYQT, QT_API_PYSIDE + +# Now peform the imports. +if QT_API == QT_API_PYQT: + from PyQt4.QtWebKit import * # analysis:ignore +elif QT_API == QT_API_PYSIDE: + from PySide.QtWebKit import * # analysis:ignore diff -Nru taurus-3.0.0/lib/taurus/qt/Qwt5.py taurus-3.1.0/lib/taurus/qt/Qwt5.py --- taurus-3.0.0/lib/taurus/qt/Qwt5.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/Qwt5.py 2013-07-25 07:53:41.000000000 +0000 @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""This module exposes PyQt4.QtSvg module""" + +from taurusqtoptions import QT_API, QT_API_PYQT, QT_API_PYSIDE + +# Now peform the imports. +if QT_API == QT_API_PYQT: + from PyQt4.Qwt5 import * +elif QT_API == QT_API_PYSIDE: + from PySide.Qwt5 import * diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/communication/communication.py taurus-3.1.0/lib/taurus/qt/qtcore/communication/communication.py --- taurus-3.0.0/lib/taurus/qt/qtcore/communication/communication.py 2012-04-30 07:47:14.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/communication/communication.py 2013-07-25 07:53:41.000000000 +0000 @@ -28,7 +28,7 @@ """ from taurus.qt import QtCore -import weakref, copy +import weakref _DEBUG = False @@ -53,8 +53,6 @@ self.__dataUID = dataUID self.__data = defaultData self.__isDataSet = False - self.__readers = 0 - self.__writers = 0 self.__readerSlots = [] self.__writerSignals = [] @@ -104,8 +102,8 @@ ''' self.connect(self, QtCore.SIGNAL("dataChanged"), slot) if readOnConnect and self.__isDataSet: slot(self.__data) - self.__readers += 1 - self.__readerSlots.append(weakref.ref(slot)) + obj=getattr(slot,'__self__',slot) + self.__readerSlots.append((weakref.ref(obj), slot.__name__)) def connectWriter(self, writer, signalname): ''' @@ -120,7 +118,6 @@ .. seealso:: :meth:`connectReader`, :meth:`setData` ''' self.connect(writer, QtCore.SIGNAL(signalname),self.setData) - self.__writers += 1 self.__writerSignals.append((weakref.ref(writer),signalname)) def disconnectWriter(self, writer, signalname): @@ -132,7 +129,6 @@ .. seealso:: :meth:`SharedDataManager.disconnectWriter` ''' ok = self.disconnect(writer, QtCore.SIGNAL(signalname), self.setData) - if ok: self.__writers -= 1 self.__writerSignals.remove((weakref.ref(writer),signalname)) def disconnectReader(self, slot): @@ -144,18 +140,32 @@ .. seealso:: :meth:`SharedDataManager.disconnectReader`, :meth:`getData` ''' ok = self.disconnect(self, QtCore.SIGNAL("dataChanged"), slot) - if ok: self.__readers -= 1 - self.__readerSlots.remove(weakref.ref(slot)) + self.__readerSlots.remove((weakref.ref(slot.__self__),slot.__name__)) def isDataSet(self): - '''Whether the data has been set at least once or if it is uninitialized''' + '''Whether the data has been set at least once or if it is uninitialized + + :return: (bool) True if the data has been set. False it is uninitialized''' return self.__isDataSet def info(self): - return "MODEL: %s\n\t Readers (%i): %s\n\t Writers (%i):%s\n"%(self.__repr__(), len(self.__readerSlots), - repr(self.__readerSlots), len(self.__writerSignals), - repr(self.__writerSignals)) + readers=["%s::%s"%(repr(r()),s) for r,s in self.__readerSlots] + writers=["%s::%s"%(repr(r()),s) for r,s in self.__writerSignals] + return "UID: %s\n\t Readers (%i):%s\n\t Writers (%i):%s\n"%(self.__dataUID, len(readers), + readers, len(writers), writers) + def readerCount(self): + '''returns the number of currently registered readers of this model + + :return: (int) + ''' + return len(self.__readerSlots) + + def writerCount(self): + '''returns the number of currently registered writers of this model + :return: (int) + ''' + return len(self.__writerSignals) class SharedDataManager(QtCore.QObject): @@ -167,7 +177,7 @@ ''' def __init__(self, parent): QtCore.QObject.__init__(self, parent) - self.__models = weakref.WeakValueDictionary() + self.__models = {} def __getDataModel(self, dataUID): @@ -188,6 +198,26 @@ self.__models[dataUID] = DataModel(self,dataUID) return self.__models[dataUID] + def getDataModelProxy(self, dataUID, callback=None): + ''' + Returns a :class:`weakref.proxy` to a :class:`DataModel` object for the + given data UID or None if the UID is not registered. + + .. note:: The underlying :class:`DataModel` object may cease to exist if + all its readers and writers are unregistered. + + :param dataUID: (str) the unique identifier of the data + :param callback: (callable) same as in :class:`weakref.ref` callback parameter + + :return: (weakref.proxy or None) + + .. seealso:: :meth:`connectReader`, :meth:`connectWriter`, :class:`DataModel` + ''' + if dataUID not in self.__models: + return None + dm = self.__getDataModel(dataUID) + return weakref.proxy(dm,callback) + def connectReader(self, dataUID, slot, readOnConnect=True): ''' Registers the given slot method to receive notifications whenever the @@ -247,7 +277,10 @@ .. seealso:: :meth:`DataModel.disconnectWriter` ''' - self.__getDataModel(dataUID).disconnectWriter(writer, signalname) + m = self.__getDataModel(dataUID) + m.disconnectWriter(writer, signalname) + if m.readerCount() < 1 and m.writerCount()<1: + self.__models.pop(dataUID) def disconnectReader(self, dataUID, slot): '''Unregister the given method as data receiver @@ -257,7 +290,10 @@ .. seealso:: :meth:`DataModel.disconnectReader` ''' - self.__getDataModel(dataUID).disconnectReader(slot) + m = self.__getDataModel(dataUID) + m.disconnectReader(slot) + if m.readerCount() < 1 and m.writerCount()<1: + self.__models.pop(dataUID) def activeDataUIDs(self): ''' @@ -277,8 +313,8 @@ def info(self): s="" - for uid,m in self.__models.iteritems(): - s+=m.info() + for uid,m in sorted(self.__models.iteritems()): + s+=m.info()+'\n' return s \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/configuration/configuration.py taurus-3.1.0/lib/taurus/qt/qtcore/configuration/configuration.py --- taurus-3.0.0/lib/taurus/qt/qtcore/configuration/configuration.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/configuration/configuration.py 2013-07-25 07:53:41.000000000 +0000 @@ -50,12 +50,14 @@ else: result = self.fget() return result + def applyConfig(self, value, depth=-1): '''calls the fset function for this property with the given value. The depth parameter is ignored''' if isinstance(self.fget, basestring):# fget is not a method but a method name... getattr(self._obj, self.fset)(value) else: self.fset(value) + def objectName(self): '''returns the name of this property''' return self.name @@ -122,8 +124,11 @@ implementing "perspectives" in your application. ''' + + defaultConfigRecursionDepth = -1 + _supportedConfigVersions = ("__UNVERSIONED__",)#the latest element of this list is considered the current version + def __init__(self): - self._supportedConfigVersions = ["__UNVERSIONED__"] #the latest element of this list is considered the current version self.resetConfigurableItems() @staticmethod @@ -185,7 +190,7 @@ configdict["__orderedConfigNames__"] = self.__configurableItemNames return configdict - def applyConfig(self, configdict, depth=-1): + def applyConfig(self, configdict, depth=None): """applies the settings stored in a configdict to the current object. In most usual situations, using :meth:`registerConfigProperty` and @@ -198,12 +203,17 @@ for this object, and not for any other object registered via :meth:`registerConfigurableItem`. If depth > 0, applyConfig will be called recursively as many times as - the depth value. If depth < 0 (default), no limit is - imposed to recursion (i.e., it will recurse for as deep as - there are registered items) + the depth value. If depth < 0 (default, see note), no + limit is imposed to recursion (i.e., it will recurse for + as deep as there are registered items). + + .. note:: the default recursion depth can be tweaked in derived classes + by changing the class property `defaultConfigRecursionDepth` .. seealso:: :meth:`createConfig` """ + if depth is None: + depth = self.defaultConfigRecursionDepth if not self.checkConfigVersion(configdict): raise ValueError('the given configuration is of unsupported version') #delegate restoring the configuration of any registered configurable item @@ -318,6 +328,9 @@ :param item: (object or str) The object that should be unregistered. Alternatively, the name under which the object was registered can be passed as a python string. + :param raiseOnError: (bool) If True (default), it raises a KeyError + exception if item was not registered. If False, it + just logs a debug message .. seealso:: :meth:`registerConfigProperty`, :meth:`registerConfigDelegate` ''' @@ -330,7 +343,7 @@ elif raiseOnError: raise KeyError('"%s" was not registered.'%name) else: - self.info('"%s" was not registered. Skipping'%name) + self.debug('"%s" was not registered. Skipping'%name) return False @@ -399,8 +412,8 @@ import cPickle as pickle if ofile is None: from taurus.qt import Qt - ofile = Qt.QFileDialog.getSaveFileName( self, 'Save Configuration', '%s.pck'%self.__class__.__name__, 'Configuration File (*.pck)') - if ofile.isEmpty(): return + ofile = unicode(Qt.QFileDialog.getSaveFileName( self, 'Save Configuration', '%s.pck'%self.__class__.__name__, 'Configuration File (*.pck)')) + if not ofile: return if not isinstance(ofile,file): ofile=open(ofile,'w') configdict=self.createConfig(allowUnpickable=False) self.info("Saving current settings in '%s'"%ofile.name) @@ -417,8 +430,8 @@ import cPickle as pickle if ifile is None: from taurus.qt import Qt - ifile = Qt.QFileDialog.getOpenFileName( self, 'Load Configuration', '', 'Configuration File (*.pck)') - if ifile.isEmpty(): return + ifile = unicode(Qt.QFileDialog.getOpenFileName( self, 'Load Configuration', '', 'Configuration File (*.pck)')) + if not ifile: return if not isinstance(ifile,file): ifile=open(ifile,'r') configdict=pickle.load(ifile) self.applyConfig(configdict) diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/model/taurusdatabasemodel.py taurus-3.1.0/lib/taurus/qt/qtcore/model/taurusdatabasemodel.py --- taurus-3.0.0/lib/taurus/qt/qtcore/model/taurusdatabasemodel.py 2012-04-30 07:47:14.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/model/taurusdatabasemodel.py 2013-07-25 07:53:41.000000000 +0000 @@ -3,21 +3,21 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## @@ -39,13 +39,14 @@ __docformat__ = 'restructuredtext' from taurus.qt import Qt -import taurus.core +from taurus.core.taurusbasetypes import TaurusElementType, TaurusSWDevHealth +from taurus.core.taurusdatabase import TaurusInfo, TaurusDatabase import taurus.qt.qtcore.mimetypes -from taurusmodel import TaurusBaseTreeItem, TaurusBaseModel, TaurusBaseProxyModel +from .taurusmodel import TaurusBaseTreeItem, TaurusBaseModel, TaurusBaseProxyModel -ElemType = taurus.core.TaurusElementType -DevHealth = taurus.core.TaurusSWDevHealth +ElemType = TaurusElementType +DevHealth = TaurusSWDevHealth def getElementTypeIcon(*args, **kwargs): """Wrapper to prevent loading qtgui when this module is imported""" @@ -74,7 +75,7 @@ class TaurusTreeDbBaseItem(TaurusBaseTreeItem): - DisplayFunc = taurus.core.TaurusInfo.name + DisplayFunc = TaurusInfo.name class TaurusTreeDevicePartItem(TaurusTreeDbBaseItem): @@ -83,10 +84,10 @@ def data(self, index): column = index.column() if column > 0: return - + model = index.model() role = model.role(column, self.depth()) - + if role == self.role(): return self._itemData @@ -102,7 +103,7 @@ def role(self): return ElemType.Domain - + class TaurusTreeDeviceFamilyItem(TaurusTreeDevicePartItem): """A node designed to represent a the family part of a device name""" @@ -123,10 +124,10 @@ class TaurusTreeSimpleDeviceItem(TaurusTreeDbBaseItem): """A node designed to represent a device (without any child nodes)""" - + def hasChildren(self): return False - + def childCount(self): return 0 @@ -162,7 +163,7 @@ class TaurusTreeDeviceItem(TaurusTreeDbBaseItem): """A node designed to represent a device""" - + SearchForAttributeHealth = DevHealth.Exported, DevHealth.ExportedAlive, \ DevHealth.NotExportedAlive @@ -179,7 +180,7 @@ if not data.health() in self.SearchForAttributeHealth: return False return True - + def childCount(self): nb = super(TaurusTreeDeviceItem, self).childCount() if nb > 0: @@ -189,7 +190,7 @@ return 0 self.updateChilds() return super(TaurusTreeDeviceItem, self).childCount() - + def updateChilds(self): if len(self._childItems) > 0: return @@ -230,7 +231,7 @@ class TaurusTreeAttributeItem(TaurusTreeDbBaseItem): """A node designed to represent an attribute""" - + def data(self, index): column, model = index.column(), index.model() role = model.role(column, self.depth()) @@ -241,7 +242,7 @@ if data_info and hasattr(data_info, 'label'): ret = "'" + data_info.label + "' (" + ret + ")" return ret - + def toolTip(self, index): if index.column() > 0: return TaurusTreeDbBaseItem.toolTip(self, index) @@ -257,28 +258,28 @@ limits = "[%s, %s]" % (di.min_value, di.max_value), alarms = "[%s, %s]" % (di.alarms.min_alarm, di.alarms.max_alarm), warnings = "[%s, %s]" % (di.alarms.min_warning, di.alarms.max_warning),) - + for id, value in items.items(): ret += '%s:%s' % (id.capitalize(), value) ret += '' return ret - + def mimeData(self, index): return self.itemData().fullName() - + def role(self): return ElemType.Attribute - - + + class TaurusTreeServerNameItem(TaurusTreeDbBaseItem): """A node designed to represent the server name part of a server""" - + DisplayFunc = str - + def data(self, index): column, model = index.column(), index.model() role = model.role(column, self.depth()) - + if role == ElemType.ServerName or role == ElemType.Name: return self._itemData @@ -288,11 +289,11 @@ class TaurusTreeServerItem(TaurusTreeDbBaseItem): """A node designed to represent a server""" - + def data(self, index): column, model = index.column(), index.model() role = model.role(column, self.depth()) - + if role == ElemType.Server or role == ElemType.Name: return self._itemData.name() elif role == ElemType.ServerName: @@ -303,7 +304,7 @@ return self._itemData.health() elif role == ElemType.Host: return self._itemData.host() - + def mimeData(self, index): return self.itemData().fullName() @@ -313,11 +314,11 @@ class TaurusTreeFullServerItem(TaurusTreeDbBaseItem): """A node designed to represent a server""" - + def data(self, index): column, model = index.column(), index.model() role = model.role(column, self.depth()) - + if role == ElemType.Server or role == ElemType.Name: return self._itemData.fullName() elif role == ElemType.ServerName: @@ -338,11 +339,11 @@ class TaurusTreeDeviceClassItem(TaurusTreeDbBaseItem): """A node designed to represent a device class""" - + def data(self, index): column, model = index.column(), index.model() role = model.role(column, self.depth()) - + if role == ElemType.Name or role == ElemType.DeviceClass: return self._itemData.name() @@ -357,31 +358,31 @@ """The base class for all Taurus database Qt models. By default, this model represents a plain device perspective of the underlying database.""" - + ColumnNames = "Device", "Alias", "Server", "Class", "Alive", "Host" ColumnRoles = (ElemType.Device, ElemType.Device), ElemType.DeviceAlias, ElemType.Server, ElemType.DeviceClass, ElemType.Exported, ElemType.Host def createNewRootItem(self): return TaurusTreeDbBaseItem(self, self.ColumnNames) - + def refresh(self, refresh_source=False): data = self.dataSource() if refresh_source and data is not None: data.refreshCache() TaurusBaseModel.refresh(self, refresh_source=refresh_source) - + def roleIcon(self, taurus_role): return getElementTypeIcon(taurus_role) - + def columnIcon(self, column): return self.roleIcon(self.role(column)) - + def roleToolTip(self, taurus_role): return getElementTypeToolTip(taurus_role) def columnToolTip(self, column): return self.roleToolTip(self.role(column)) - + def roleSize(self, taurus_role): return getElementTypeSize(taurus_role) @@ -389,7 +390,7 @@ taurus_role = self.role(column) s = self.roleSize(taurus_role) return s - + def mimeTypes(self): return ["text/plain", taurus.qt.qtcore.mimetypes.TAURUS_MODEL_LIST_MIME_TYPE, taurus.qt.qtcore.mimetypes.TAURUS_MODEL_MIME_TYPE] @@ -415,11 +416,11 @@ def pyData(self, index, role): if not index.isValid(): return None - + item = index.internalPointer() row, column, depth = index.row(), index.column(), item.depth() taurus_role = self.role(column, depth) - + ret = None if role == Qt.Qt.DisplayRole: if taurus_role != ElemType.Exported: @@ -448,10 +449,10 @@ def setupModelData(self, data): if data is None: return - if isinstance(data, taurus.core.TaurusDatabase): + if isinstance(data, TaurusDatabase): data = data.cache() devices = data.devices() - + rootItem = self._rootItem for dev_name in data.getDeviceNames(): dev = devices[dev_name] @@ -462,25 +463,25 @@ class TaurusDbSimpleDeviceModel(TaurusDbBaseModel): """A Qt model that structures device elements in 1 level tree with device name as node leafs. This model contains only 1 column.""" - + ColumnNames = "Device", ColumnRoles = (ElemType.Device, ElemType.Device), - + class TaurusDbSimpleDeviceAliasModel(TaurusDbBaseModel): """A Qt model that structures device elements in 1 level tree with device alias as node leafs. This model contains only 1 column.""" - + ColumnNames = "Alias", ColumnRoles = (ElemType.DeviceAlias, ElemType.DeviceAlias), - + def setupModelData(self, data): if data is None: return - if isinstance(data, taurus.core.TaurusDatabase): + if isinstance(data, TaurusDatabase): data = data.cache() devices = data.devices() - + rootItem = self._rootItem for dev_name in data.getDeviceNames(): dev = devices[dev_name] @@ -492,28 +493,28 @@ class TaurusDbPlainDeviceModel(TaurusDbBaseModel): """A Qt model that structures device elements in 1 level tree. Device nodes will have attribute child nodes if the device is running.""" - + ColumnNames = "Device", "Alias", "Server", "Class", "Alive", "Host" ColumnRoles = (ElemType.Device, ElemType.Device, ElemType.Attribute), ElemType.DeviceAlias, ElemType.Server, ElemType.DeviceClass, ElemType.Exported, ElemType.Host def setupModelData(self, data): if data is None: return - if isinstance(data, taurus.core.TaurusDatabase): + if isinstance(data, TaurusDatabase): data = data.cache() devices = data.devices() - + rootItem = self._rootItem for dev_name in data.getDeviceNames(): dev = devices[dev_name] devItem = TaurusTreeDeviceItem(self, dev, rootItem) rootItem.appendChild(devItem) - + class TaurusDbDeviceModel(TaurusDbBaseModel): """A Qt model that structures device elements is a 3 level tree organized as: - + - - - """ @@ -522,9 +523,9 @@ def setupModelData(self, data): if data is None: return - if isinstance(data, taurus.core.TaurusDatabase): + if isinstance(data, TaurusDatabase): data = data.deviceTree() - + rootItem = self._rootItem for domain in sorted(data.keys()): families = data[domain] @@ -543,26 +544,26 @@ class TaurusDbPlainServerModel(TaurusDbBaseModel): ColumnNames = "Server", "Alive", "Host" ColumnRoles = (ElemType.Server, ElemType.ServerInstance), ElemType.Exported, ElemType.Host - + def setupModelData(self, data): if data is None: return - if isinstance(data, taurus.core.TaurusDatabase): + if isinstance(data, TaurusDatabase): data = data.cache() - + servers = data.servers() rootItem = self._rootItem - + for server_name, server in servers.items(): serverInstanceItem = TaurusTreeFullServerItem(self, server, rootItem) rootItem.appendChild(serverInstanceItem) - - + + class TaurusDbServerModel(TaurusDbBaseModel): """A Qt model that structures server elements in a tree organized as: - + - - - @@ -571,33 +572,33 @@ ColumnNames = "Server", "Alive", "Host" ColumnRoles = (ElemType.Server, ElemType.ServerName, ElemType.ServerInstance, ElemType.DeviceClass, ElemType.Device, ElemType.Attribute), ElemType.Exported, ElemType.Host - + def setupModelData(self, data): if data is None: return - if isinstance(data, taurus.core.TaurusDatabase): + if isinstance(data, TaurusDatabase): data = data.cache() - + servers, klasses, devices = data.servers(), data.klasses(), data.devices() rootItem = self._rootItem server_dict = {} - + server_names = data.getServerNames() for server_name in server_names: server = servers[server_name] name, instance = server.serverName(), server.serverInstance() - + serverNameItem = server_dict.get(name) if serverNameItem is None: serverNameItem = TaurusTreeServerNameItem(self, name, rootItem) rootItem.appendChild(serverNameItem) server_dict[name] = serverNameItem #rootItem.appendChild(serverNameItem) - + serverInstanceItem = TaurusTreeServerItem(self, server, serverNameItem) serverNameItem.appendChild(serverInstanceItem) - + klass_names = server.getClassNames() device_names = server.getDeviceNames() for klass_name in klass_names: @@ -613,20 +614,20 @@ class TaurusDbDeviceClassModel(TaurusDbBaseModel): """A Qt model that structures class elements in a tree organized as: - + * * * """ ColumnNames = "Class", "Alive", "Host" ColumnRoles = (ElemType.DeviceClass, ElemType.DeviceClass, ElemType.Device, ElemType.Attribute), ElemType.Exported, ElemType.Host - + def setupModelData(self, data): if data is None: return - - if isinstance(data, taurus.core.TaurusDatabase): + + if isinstance(data, TaurusDatabase): data = data.cache() - + rootItem = self._rootItem klasses, devices = data.klasses(), data.devices() dev_nb = 0 @@ -651,76 +652,81 @@ - TaurusDbDeviceModel - TaurusDbSimpleDeviceModel - TaurusDbPlainDeviceModel""" - + def filterAcceptsRow(self, sourceRow, sourceParent): sourceModel = self.sourceModel() idx = sourceModel.index(sourceRow, 0, sourceParent) treeItem = idx.internalPointer() - expr = self.filterRegExp() - + regexp = self.filterRegExp() + # if domain node, check if it will potentially have any children if isinstance(treeItem, TaurusTreeDeviceDomainItem): domain = treeItem.display() devices = sourceModel.getDomainDevices(domain) for device in devices: - if self.deviceMatches(device, expr): + if self.deviceMatches(device, regexp): return True return False - + # if family node, check if it will potentially have any children if isinstance(treeItem, TaurusTreeDeviceFamilyItem): domain = treeItem.parent().display() family = treeItem.display() devices = sourceModel.getFamilyDevices(domain, family) for device in devices: - if self.deviceMatches(device, expr): + if self.deviceMatches(device, regexp): return True return False - + if isinstance(treeItem, TaurusTreeDeviceItem) or \ isinstance(treeItem, TaurusTreeSimpleDeviceItem) or \ isinstance(treeItem, TaurusTreeDeviceMemberItem): device = treeItem.itemData() - return self.deviceMatches(device, expr) + return self.deviceMatches(device, regexp) return True - - def deviceMatches(self, device, expr): + + def deviceMatches(self, device, regexp): name = device.name() - if Qt.QString(name).contains(expr): + + # if Qt.QString(name).contains(regexp): + if regexp.indexIn(name) != -1: return True name = device.alias() if name is None: return False - return Qt.QString(name).contains(expr) + #return Qt.QString(name).contains(regexp) + return regexp.indexIn(name) != -1 class TaurusDbServerProxyModel(TaurusDbBaseProxyModel): """A Qt filter & sort model for the TaurusDbServerModel""" - + def filterAcceptsRow(self, sourceRow, sourceParent): sourceModel = self.sourceModel() idx = sourceModel.index(sourceRow, 0, sourceParent) treeItem = idx.internalPointer() - expr = self.filterRegExp() - + regexp = self.filterRegExp() + # if server name node, check if it will potentially have any children if isinstance(treeItem, TaurusTreeServerNameItem): serverName = treeItem.display() serverInstances = sourceModel.getServerNameInstances(serverName) for serverInstance in serverInstances: - if Qt.QString(serverInstance.name()).contains(expr): + #if Qt.QString(serverInstance.name()).contains(regexp): + if regexp.indexIn(serverInstance.name()) != -1: return True return False - + if isinstance(treeItem, TaurusTreeServerItem): - return treeItem.qdisplay().contains(expr) + #return treeItem.qdisplay().contains(regexp) + return regexp.indexIn(treeItem.qdisplay()) != -1 return True class TaurusDbDeviceClassProxyModel(TaurusDbBaseProxyModel): """A Qt filter & sort model for the TaurusDbDeviceClassModel""" - + def filterAcceptsRow(self, sourceRow, sourceParent): sourceModel = self.sourceModel() idx = sourceModel.index(sourceRow, 0, sourceParent) @@ -728,7 +734,8 @@ if not isinstance(treeItem, TaurusTreeDeviceClassItem): return True - - expr = self.filterRegExp() - return treeItem.qdisplay().contains(expr) + regexp = self.filterRegExp() + + #return treeItem.qdisplay().contains(regexp) + return regexp.indexIn(treeItem.qdisplay()) != -1 diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/model/taurusmodel.py taurus-3.1.0/lib/taurus/qt/qtcore/model/taurusmodel.py --- taurus-3.0.0/lib/taurus/qt/qtcore/model/taurusmodel.py 2012-04-30 07:47:14.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/model/taurusmodel.py 2013-07-25 07:53:41.000000000 +0000 @@ -30,7 +30,10 @@ __docformat__ = 'restructuredtext' from taurus.qt import Qt -from taurus.core.util import Logger +from taurus.core.taurusbasetypes import TaurusElementType +from taurus.core.util.log import Logger + +QtQt = Qt.Qt class TaurusBaseTreeItem(object): """A generic node""" @@ -151,13 +154,13 @@ def role(self): """Returns the prefered role for the item. - This implementation returns taurus.core.TaurusElementType.Unknown + This implementation returns taurus.core.taurusbasetypes.TaurusElementType.Unknown This method should be able to return any kind of python object as long as the model that is used is compatible. - :return: (taurus.core.TaurusElementType) the role in form of element type""" - return ElemType.Unknown + :return: (taurus.core.taurusbasetypes.TaurusElementType) the role in form of element type""" + return TaurusElementType.Unknown def __str__(self): return self.display() @@ -190,7 +193,7 @@ return getattr(self.dataSource(), name) def createNewRootItem(self): - return TaurusTreeBaseItem(self, self.ColumnNames) + return TaurusBaseTreeItem(self, self.ColumnNames) def refresh(self, refresh_source=False): self.beginResetModel() @@ -247,35 +250,35 @@ s = self.roleSize(role) return s - def pyData(self, index, role=Qt.Qt.DisplayRole): + def pyData(self, index, role=QtQt.DisplayRole): if not index.isValid(): return None item = index.internalPointer() ret = None - if role == Qt.Qt.DisplayRole or role == Qt.Qt.EditRole: + if role == QtQt.DisplayRole or role == QtQt.EditRole: ret = item.data(index) -# elif role == Qt.Qt.CheckStateRole: +# elif role == QtQt.CheckStateRole: # data = item.data(index) # if type(data) != bool: # data = str(data).lower() == 'true' -# ret = Qt.Qt.Unchecked +# ret = QtQt.Unchecked # if data == True: -# ret = Qt.Qt.Checked - elif role == Qt.Qt.DecorationRole: +# ret = QtQt.Checked + elif role == QtQt.DecorationRole: ret = item.icon(index) - elif role == Qt.Qt.ToolTipRole: + elif role == QtQt.ToolTipRole: ret = item.toolTip(index) - #elif role == Qt.Qt.SizeHintRole: + #elif role == QtQt.SizeHintRole: # ret = self.columnSize(column) - elif role == Qt.Qt.FontRole: + elif role == QtQt.FontRole: ret = self.DftFont - elif role == Qt.Qt.UserRole: + elif role == QtQt.UserRole: ret = Qt.QVariant(item) return ret - def data(self, index, role=Qt.Qt.DisplayRole): + def data(self, index, role=QtQt.DisplayRole): ret = self.pyData(index, role) if ret is None: ret = Qt.QVariant() @@ -283,9 +286,9 @@ ret = Qt.QVariant(ret) return ret - def _setData(self, index, qvalue, role=Qt.Qt.EditRole): + def _setData(self, index, qvalue, role=QtQt.EditRole): item = index.internalPointer() - pyobj = qvalue.toPyObject() + pyobj = Qt.from_qvariant(qvalue) if pyobj is NotImplemented: self.warning("Failed attempt to convert a QValue. Maybe it is due to Qt<4.6") item.setData(index, pyobj) @@ -295,29 +298,29 @@ if not index.isValid(): return 0 - ret = Qt.Qt.ItemIsEnabled | Qt.Qt.ItemIsDragEnabled + ret = QtQt.ItemIsEnabled | QtQt.ItemIsDragEnabled item = index.internalPointer() column, depth = index.column(), item.depth() taurus_role = self.role(column, depth) if taurus_role in self.selectables(): - ret |= Qt.Qt.ItemIsSelectable + ret |= QtQt.ItemIsSelectable return ret - def headerData(self, section, orientation, role=Qt.Qt.DisplayRole): + def headerData(self, section, orientation, role=QtQt.DisplayRole): ret = None - if orientation == Qt.Qt.Horizontal: - if role == Qt.Qt.TextAlignmentRole: - ret = int(Qt.Qt.AlignLeft | Qt.Qt.AlignVCenter) - elif role == Qt.Qt.DisplayRole: + if orientation == QtQt.Horizontal: + if role == QtQt.TextAlignmentRole: + ret = int(QtQt.AlignLeft | QtQt.AlignVCenter) + elif role == QtQt.DisplayRole: ret = self.ColumnNames[section] - elif role == Qt.Qt.SizeHintRole: + elif role == QtQt.SizeHintRole: ret = Qt.QSize(self.columnSize(section)) ret.setHeight(24) - elif role == Qt.Qt.ToolTipRole: + elif role == QtQt.ToolTipRole: ret = self.columnToolTip(section) - elif role == Qt.Qt.DecorationRole: + elif role == QtQt.DecorationRole: ret = self.columnIcon(section) return Qt.QVariant(ret) @@ -372,22 +375,22 @@ class TaurusBaseProxyModel(Qt.QSortFilterProxyModel): - """A taurus database base Qt filter & sort model""" + """A taurus base Qt filter & sort model""" def __init__(self, parent=None): Qt.QSortFilterProxyModel.__init__(self, parent) # filter configuration - self.setFilterCaseSensitivity(Qt.Qt.CaseInsensitive) + self.setFilterCaseSensitivity(QtQt.CaseInsensitive) self.setFilterKeyColumn(0) - self.setFilterRole(Qt.Qt.DisplayRole) + self.setFilterRole(QtQt.DisplayRole) # sort configuration - self.setSortCaseSensitivity(Qt.Qt.CaseInsensitive) - self.setSortRole(Qt.Qt.DisplayRole) + self.setSortCaseSensitivity(QtQt.CaseInsensitive) + self.setSortRole(QtQt.DisplayRole) # general configuration - self.sort(0, Qt.Qt.AscendingOrder) + self.sort(0, QtQt.AscendingOrder) def __getattr__(self, name): return getattr(self.sourceModel(), name) diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/tango/sardana/macroserver.py taurus-3.1.0/lib/taurus/qt/qtcore/tango/sardana/macroserver.py --- taurus-3.0.0/lib/taurus/qt/qtcore/tango/sardana/macroserver.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/tango/sardana/macroserver.py 2013-07-25 07:53:41.000000000 +0000 @@ -27,12 +27,12 @@ __all__ = ["QDoor", "QMacroServer", "MacroServerMessageErrorHandler", "registerExtensions"] -import taurus.core +from taurus.core.taurusbasetypes import TaurusEventType from taurus.core.tango.sardana.macroserver import BaseMacroServer, BaseDoor - from taurus.qt import Qt -CHANGE_EVTS = (taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic) +CHANGE_EVTS = TaurusEventType.Change, TaurusEventType.Periodic + class QDoor(BaseDoor, Qt.QObject): @@ -56,7 +56,7 @@ def macroStatusReceived(self, s, t, v): res = BaseDoor.macroStatusReceived(self, s, t, v) - if t == taurus.core.TaurusEventType.Error: + if t == TaurusEventType.Error: macro = None else: macro = self.getRunningMacro() @@ -97,11 +97,11 @@ macros, elements = 0, 0 for element in set.union(added, removed, changed): - if "MacroCode" in element.interfaces: + if "MacroCode" in element.interfaces: macros += 1 - elements += 1 - if elements and macros: - break + elements += 1 + if elements and macros: + break if elements: self.emit(Qt.SIGNAL("elementsChanged")) if macros: @@ -121,6 +121,7 @@ # handlers, maybe in TangoFactory & TaurusManager from taurus.qt.qtgui.panel import TaurusMessageErrorHandler + class MacroServerMessageErrorHandler(TaurusMessageErrorHandler): def setError(self, err_type=None, err_value=None, err_traceback=None): @@ -139,7 +140,6 @@ exc_info = "".join(err_traceback) style = "" try: - import pygments import pygments.formatters import pygments.lexers except: diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/tango/sardana/model.py taurus-3.1.0/lib/taurus/qt/qtcore/tango/sardana/model.py --- taurus-3.0.0/lib/taurus/qt/qtcore/tango/sardana/model.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/tango/sardana/model.py 2013-07-25 07:53:41.000000000 +0000 @@ -42,9 +42,9 @@ except: pygments = None -from taurus.core import TaurusDevice +from taurus.core.taurusdevice import TaurusDevice from taurus.qt import Qt -from taurus.core.util import Enumeration +from taurus.core.util.enumeration import Enumeration from taurus.qt.qtcore.model import TaurusBaseTreeItem, TaurusBaseModel, \ TaurusBaseProxyModel from taurus.qt.qtcore.mimetypes import TAURUS_MODEL_LIST_MIME_TYPE, \ @@ -68,7 +68,7 @@ "CommunicationChannel" : ("Communication channels", _TNG, "Communication channel",), "MacroLibrary" : ("Macro libraries", _MOD, "Macro library",), "MacroClass" : ("Macro classes", _CLS, "Macro class",), - "Instrument" : ("Instruments", _TNG, "Instrument"), + "Instrument" : ("Instruments", _TNG, "Instrument",), "MacroFunction" : ("Macro functions", _FNC, "Macro function",), } @@ -78,7 +78,7 @@ def getElementTypeIcon(t): import taurus.qt.qtgui.resource try: - return taurus.qt.qtgui.resource.getIcon(TYPE_MAP.get(t, _TNG)[1]) + return taurus.qt.qtgui.resource.getIcon(TYPE_MAP.get(t, (None,_TNG))[1]) except: return None @@ -86,7 +86,7 @@ return Qt.QSize(200,24) def getElementTypeToolTip(t): - return TYPE_MAP.get(t, 'no information')[2] + return TYPE_MAP.get(t, (None,None,'no information'))[2] class SardanaBaseTreeItem(TaurusBaseTreeItem): @@ -103,7 +103,7 @@ def role(self): """Returns the prefered role for the item. - This implementation returns taurus.core.TaurusElementType.Unknown + This implementation returns taurus.core.taurusbasetypes.TaurusElementType.Unknown This method should be able to return any kind of python object as long as the model that is used is compatible. diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/tango/sardana/pool.py taurus-3.1.0/lib/taurus/qt/qtcore/tango/sardana/pool.py --- taurus-3.0.0/lib/taurus/qt/qtcore/tango/sardana/pool.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/tango/sardana/pool.py 2013-07-25 07:53:41.000000000 +0000 @@ -32,7 +32,7 @@ from taurus.qt import Qt -from taurus.core import TaurusEventType +from taurus.core.taurusbasetypes import TaurusEventType from taurus.core.tango import TangoDevice CHANGE_EVTS = TaurusEventType.Change, TaurusEventType.Periodic diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/taurusqlistener.py taurus-3.1.0/lib/taurus/qt/qtcore/taurusqlistener.py --- taurus-3.0.0/lib/taurus/qt/qtcore/taurusqlistener.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/taurusqlistener.py 2013-07-25 07:53:41.000000000 +0000 @@ -0,0 +1,201 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +"""""" + +from __future__ import print_function + +__all__ = ["QTaurusBaseListener", "QObjectTaurusListener"] + +__docformat__ = 'restructuredtext' + +from taurus.core.tauruslistener import TaurusListener +from taurus.qt import Qt + + +class QTaurusBaseListener(TaurusListener): + """Base class for QObjects listening to taurus events. It is not + instanciable! Use a class that inherits from Qt class and from this class + (example: :class:`QObjectTaurusListener`)""" + + def __init__(self, name=None, parent=None): + if name is None: + name = self.__class__.__name__ + super(QTaurusBaseListener, self).__init__(name, parent=parent) + self._eventFilters = [] + Qt.QObject.connect(self.getSignaller(), Qt.SIGNAL('taurusEvent'), + self.filterEvent) + + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + # Event handling chain + #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- + + def eventReceived(self, evt_src, evt_type, evt_value): + """The basic implementation of the event handling chain is as + follows: + + - eventReceived just calls :meth:`fireEvent` which emits a "taurusEvent" + PyQt signal that is connected (by :meth:`preAttach`) to the + :meth:`filterEvent` method. + - After filtering, :meth:`handleEvent` is invoked with the resulting + filtered event + + .. note:: + in the earlier steps of the chain (i.e., in :meth:`eventReceived`/:meth:`fireEvent`), + the code is executed in a Python thread, while from eventFilter + ahead, the code is executed in a Qt thread. + When writing widgets, one should normally work on the Qt thread + (i.e. reimplementing :meth:`handleEvent`) + + :param evt_src: (object) object that triggered the event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType) type of event + :param evt_value: (object) event value + """ + self.fireEvent(evt_src, evt_type, evt_value) + + def fireEvent(self, evt_src = None, evt_type = None, evt_value = None): + """Emits a "taurusEvent" signal. + It is unlikely that you may need to reimplement this method in subclasses. + Consider reimplementing :meth:`eventReceived` or :meth:`handleEvent` + instead depending on whether you need to execute code in the python + or Qt threads, respectively + + :param evt_src: (object or None) object that triggered the event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType or None) type of event + :param evt_value: (object or None) event value + """ + try: + emmiter = self.getSignaller() + emmiter.emit(Qt.SIGNAL('taurusEvent'), evt_src, evt_type, evt_value) + except: + pass + + def filterEvent(self, evt_src=-1, evt_type=-1, evt_value=-1): + """The event is processed by each and all filters in strict order + unless one of them returns None (in which case the event is discarded) + + :param evt_src: (object) object that triggered the event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType) type of event + :param evt_value: (object) event value + """ + r = evt_src, evt_type, evt_value + + if r == (-1,-1,-1): + # @todo In an ideal world the signature of this method should be + # (evt_src, evt_type, evt_value). However there's a bug in PyQt: + # If a signal is disconnected between the moment it is emitted and + # the moment the slot is called, then the slot is called without + # parameters (!?). We added this default values to detect if + # this is the case without printing an error message each time. + # If this gets fixed, we should remove this line. + return + + for f in self._eventFilters: + r = f(*r) + if r is None: return + self.handleEvent(*r) + + def handleEvent(self, evt_src, evt_type, evt_value): + """Event handling. Default implementation does nothing. + Reimplement as necessary + + :param evt_src: (object or None) object that triggered the event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType or None) type of event + :param evt_value: (object or None) event value + """ + pass + + def setEventFilters(self, filters = None): + """sets the taurus event filters list. + The filters are run in order, using each output to feed the next filter. + A filter must be a function that accepts 3 arguments ``(evt_src, evt_type, evt_value)`` + If the event is to be ignored, the filter must return None. + If the event is not to be ignored, filter must return a + ``(evt_src, evt_type, evt_value)`` tuple which may (or not) differ from the input. + + For a library of common filters, see taurus/core/util/eventfilters.py + + :param filters: (sequence) a sequence of filters + + See also: insertEventFilter + """ + if filters is None: filters = [] + self._eventFilters = list(filters) + + def getEventFilters(self): + """Returns the list of event filters for this widget + + :return: (sequence) the event filters + """ + return self._eventFilters + + def insertEventFilter(self, filter, index=-1): + """insert a filter in a given position + + :param filter: (callable(evt_src, evt_type, evt_value)) a filter + :param index: (int) index to place the filter (default = -1 meaning place at the end) + + See also: setEventFilters + """ + self._eventFilters.insert(index, filter) + + def getSignaller(self): + '''Reimplement this method if your derived class does not inherit from + QObject. The return value should be a permanent object capable of + emitting Qt signals. See :class:`TaurusImageItem` as an example + ''' + return self + + +class QObjectTaurusListener(Qt.QObject, QTaurusBaseListener): + + def __init__(self, name=None, parent=None): + self.call__init__wo_kw(Qt.QObject, parent) + self.call__init__(QTaurusBaseListener, name=name) + + +class ListenerDemo(QObjectTaurusListener): + + def eventReceived(self, evt_src, evt_type, evt_value): + self.info("New %s event from %s", taurus.core.taurusbasetypes.TaurusEventType[evt_type], evt_src) + return super(ListenerDemo, self).eventReceived(evt_src, evt_type, evt_value) + + def handleEvent(self, evt_src, evt_type, evt_value): + self.info("New %s event from %s", taurus.core.taurusbasetypes.TaurusEventType[evt_type], evt_src) + + +if __name__ == "__main__": + import time + import taurus + qlistener = ListenerDemo(name="DemoObject") + + attr = taurus.Attribute("sys/tg_test/1/double_scalar") + attr.addListener(qlistener) + + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + print("Finished!") diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/util/emitter.py taurus-3.1.0/lib/taurus/qt/qtcore/util/emitter.py --- taurus-3.0.0/lib/taurus/qt/qtcore/util/emitter.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/util/emitter.py 2013-07-25 07:53:41.000000000 +0000 @@ -1,4 +1,3 @@ - #!/usr/bin/env python ############################################################################# @@ -28,9 +27,10 @@ """ from functools import partial -from PyQt4 import Qt import taurus -from taurus.core.util import Logger,Singleton +from taurus.qt import Qt +from taurus.core.util.log import Logger +from taurus.core.util.singleton import Singleton import Queue,traceback ############################################################################### @@ -47,7 +47,7 @@ This class is used for convenience as TaurusEmitterThread standard method """ #print 'In modelSetter(%s,%s)' % (str(obj),str(model)) - if hasattr(obj,'setModel') and model: obj.setModel(model) + if hasattr(obj,'setModel') and model is not None: obj.setModel(model) return class MethodModel(object): @@ -141,13 +141,12 @@ self.name = name self.log = Logger('TaurusEmitterThread(%s)'%self.name) self.log.setLogLevel(self.log.Info) - self.log.info('At TaurusEmitterThread.__init__(%s)'%self.name) self.queue = queue or Queue.Queue() self.todo = Queue.Queue() self.method = method self.cursor = Qt.QCursor(Qt.Qt.WaitCursor) if cursor is True else cursor self._cursor = False - self.sleep = sleep + self.timewait = sleep self.emitter = Qt.QObject() self.emitter.moveToThread(Qt.QApplication.instance().thread()) @@ -165,13 +164,34 @@ def getDone(self): """ Returns % of done tasks in 0-1 range """ return self._done/(self._done+self.getQueue().qsize()) if self._done else 0. + + def clear(self): + while not self.todo.empty(): + self.todo.get() + while not self.getQueue().empty(): + self.getQueue().get() + self._done+=1 + + def purge(obj): + nqueue = Queue.Queue() + while not self.todo.empty(): + i = self.todo.get() + if obj not in i: + nqueue.put(i) + while not self.queue.empty(): + i = self.queue.get() + if obj not in i: + nqueue.put(i) + while not nqueue.empty(): + self.queue.put(nqueue.get()) + self.next() - def _doSomething(self,args): - self.log.debug('At TaurusEmitterThread._doSomething(%s)'%str(args)) + def _doSomething(self,params): + self.log.debug('At TaurusEmitterThread._doSomething(%s)'%str(params)) if not self.method: - method,args = args[0],args[1:] + method,args = params[0],params[1:] else: - method = self.method + method,args = self.method,params if method: try: method(*args) @@ -197,7 +217,7 @@ Qt.QApplication.instance().restoreOverrideCursor() self._cursor = False - except Queue.Empty,e: + except Queue.Empty: self.log.warning(traceback.format_exc()) pass except: @@ -205,7 +225,7 @@ return def run(self): - Qt.QApplication.instance().thread().wait(self.sleep) + Qt.QApplication.instance().thread().sleep(int(self.timewait/1000) if self.timewait>10 else int(self.timewait)) #wait(self.sleep) self.log.info('#'*80) self.log.info('At TaurusEmitterThread.run()') self.next() @@ -243,7 +263,7 @@ """ _thread = None - def __init__(self,parent=None,name='',queue=None,method=None,cursor=None,sleep=5000,log=Logger.Warning): + def __init__(self,parent=None,name='',queue=None,method=None,cursor=None,sleep=5000,log=Logger.Warning,start=True): self.name = name self.log = Logger('SingletonWorker(%s)'%self.name) self.log.setLogLevel(log) @@ -255,11 +275,17 @@ SingletonWorker._thread = TaurusEmitterThread(parent,name='SingletonWorker',cursor=cursor,sleep=sleep) self.thread = SingletonWorker._thread self.queue = queue or Queue.Queue() - - return + if start: self.start() - def next(self): - if self.queue.empty(): return + def put(self,item,block=True,timeout=None): + self.getQueue().put(item,block,timeout) + + def size(self): + self.getQueue().qsize() + + def next(self,item=None): + if item is not None: self.put(item) + elif self.queue.empty(): return msg = 'At SingletonWorker.next(), %d items not passed yet to Emitter.' % self.queue.qsize() self.log.info(msg) #(queue.empty() and self.log.info or self.log.debug)(msg) @@ -274,9 +300,8 @@ i+=1 self.log.info('%d Items added to emitter queue' % i) self.thread.emitter.emit(Qt.SIGNAL("newQueue")) - except Queue.Empty,e: + except Queue.Empty: self.log.warning(traceback.format_exc()) - pass except: self.log.warning(traceback.format_exc()) return @@ -298,11 +323,28 @@ Qt.QObject.disconnect(self.thread.emitter, Qt.SIGNAL("newQueue"), self.thread.next) self._running = False return + + def clear(self): + """ + This method will clear queue only if next() has not been called. + If you call self.thread.clear() it will clear objects for all workers!, be careful + """ + while not self.queue.empty(): self.queue.get() + #self.thread.clear() + + def purge(obj): + nqueue = Queue.Queue() + while not self.queue.empty(): + i = self.queue.get() + if obj not in i: + nqueue.put(i) + while not nqueue.empty(): + self.queue.put(nqueue.get()) def isRunning(self): return self._running def isFinished(self): return self.thread.isFinished() def finished(self): return self.thread.finished() def started(self): return self._running def terminated(self): return self.thread.terminated() - def sleep(self,ms): return self.thread.sleep(ms) + def sleep(self,s): return self.thread.sleep(s) diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/util/properties.py taurus-3.1.0/lib/taurus/qt/qtcore/util/properties.py --- taurus-3.0.0/lib/taurus/qt/qtcore/util/properties.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/util/properties.py 2013-07-25 07:53:41.000000000 +0000 @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +""" +properties.py: Methods for adding QProperties to QObjects + +A call like + set_property_methods(self,'Filters','QString',default='', + set_callback=lambda s=self:s.loadTree(s.getFilters(),clear=True), + reset_callback=lambda s=self:s.loadTree('',clear=True) + ) + +Would replace all these lines: + + def setFilters(self,filters): + self._filters = filters + self.loadTree(self._filters,clear=True) + + def getFilters(self): + return self._filters + + def resetFilters(self): + self._filters="" + self.loadTree(self._filters) + + filters = QtCore.pyqtProperty("QString", getFilters, setFilters, resetFilters) + +Not tested yet with the classical declaration: + + #model = QtCore.pyqtProperty("QString", TaurusBaseWidget.getModel, + #TaurusBaseWidget.setModel, + #TaurusBaseWidget.resetModel) + +""" + +from functools import partial +from taurus.qt import Qt +from taurus.core.tango.search import * + +def join(*seqs): + """ It returns a list containing the objects of all given sequences. """ + if len(seqs)==1 and isSequence(seqs[0]): + seqs = seqs[0] + result = [] + for seq in seqs: + if isSequence(seq): result.extend(seq) + else: result.append(seq) + # result += list(seq) + return result + +def djoin(a,b): + """ This method merges dictionaries and/or lists """ + if not any(map(isDictionary,(a,b))): return join(a,b) + other,dct = sorted((a,b),key=isDictionary) + if not isDictionary(other): + other = dict.fromkeys(other if isSequence(other) else [other,]) + for k,v in other.items(): + dct[k] = v if not k in dct else djoin(dct[k],v) + return dct + +def get_property_attribute(name): + return '_'+str(name).lower() + +def get_property(obj,name,callback=None): + return (callback and callback()) or getattr(obj,get_property_attribute(name)) + +def set_property(obj,name,value,callback=None): + #print 'set_property(%s,%s,%s,%s)'%(obj,name,value,callback) + setattr(obj,get_property_attribute(name),value) + try: callback and callback(value) + except: callback() + +def reset_property(obj,name,default=None,callback=None): + setattr(obj,get_property_attribute(name),default) + if callback: callback() + +COMMON_PROPERTIES = ( + 'ModelInConfig', #If True, it will automatically register Model + 'modifiableByUser', + #'useParentModel', #Only for widgets, not for components + #'Model', #Controlled by ModelInConfig + ) + +def set_property_methods(obj,name,type_="QString",default=None,getter=None,setter=None,reset=None,get_callback=None,set_callback=None,reset_callback=None,qt=False,config=False): + """ + This method allows to add QProperties dynamically with calls like: +
+        set_property_methods(self,'Filters','QString',default='',
+            set_callback=lambda s=self:s.loadTree(s.getFilters(),clear=True),
+            reset_callback=lambda s=self:s.loadTree('',clear=True)
+            )
+    
+ + @TODO: This method should be refactored using python descriptors/properties and types.MethodType + """ + klass = obj.__class__ + mname = '%s%s'%(name[0].upper(),name[1:]) + lname = '%s%s'%(name[0].lower(),name[1:]) + getter = getter or (lambda o=obj,n=name,c=get_callback: get_property(o,n,c)) #partial(get_property,name=name,callback=get_callback) + setter = setter or (lambda x,y=None,o=obj,d=default,n=name,c=set_callback: set_property(o,n,x if x is not obj else y,c)) #partial(set_property),name=name,callback=set_callback) + reset = reset or (lambda o=obj,n=name,d=default,c=reset_callback: reset_property(o,n,d,c)) #partial(reset_property,name=name,default=default,callback=reset_callback) + setattr(obj,'set%s'%mname,setter) + setattr(obj,'get%s'%mname,getter) + setattr(obj,'reset%s'%mname,reset) + if qt: setattr(klass,lname,Qt.pyqtProperty("QString", getter,setter,reset)) + if config: obj.registerConfigProperty(getter,setter,name) + reset() \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/qt/qtcore/util/tauruslog.py taurus-3.1.0/lib/taurus/qt/qtcore/util/tauruslog.py --- taurus-3.0.0/lib/taurus/qt/qtcore/util/tauruslog.py 2012-04-30 07:47:15.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtcore/util/tauruslog.py 2013-07-25 07:53:41.000000000 +0000 @@ -23,29 +23,29 @@ ## ############################################################################# -"""This module sets the taurus.core.util.Logger to be the Qt message handler""" +"""This module sets the taurus.core.util.log.Logger to be the Qt message handler""" __all__ = ['getQtLogger', 'initTaurusQtLogger'] __docformat__ = 'restructuredtext' from taurus.qt import Qt -import taurus.core.util +from taurus import Logger qtLogger = None QT_LEVEL_MATCHER = { - Qt.QtDebugMsg : taurus.core.util.Logger.debug, - Qt.QtWarningMsg : taurus.core.util.Logger.warning, - Qt.QtCriticalMsg : taurus.core.util.Logger.error, - Qt.QtFatalMsg : taurus.core.util.Logger.error, - Qt.QtSystemMsg : taurus.core.util.Logger.info + Qt.QtDebugMsg : Logger.debug, + Qt.QtWarningMsg : Logger.warning, + Qt.QtCriticalMsg : Logger.error, + Qt.QtFatalMsg : Logger.error, + Qt.QtSystemMsg : Logger.info } def getQtLogger(): global qtLogger if qtLogger is None: - qtLogger = taurus.core.util.Logger('QtLogger') + qtLogger = Logger('QtLogger') return qtLogger def qtTaurusMsgHandler(type, msg): diff -Nru taurus-3.0.0/lib/taurus/qt/qtdesigner/containerplugin.py taurus-3.1.0/lib/taurus/qt/qtdesigner/containerplugin.py --- taurus-3.0.0/lib/taurus/qt/qtdesigner/containerplugin.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtdesigner/containerplugin.py 2013-07-25 07:53:15.000000000 +0000 @@ -0,0 +1,124 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +""" Every TaurusWidget should have the following Qt Designer extended capabilities: + + - Task menu: + it means when you right click on the widget in the designer, it will have + the following additional items: + - 'Edit model...' - opens a customized dialog for editing the widget model + + - Property Sheet: + it means that in the Qt Designer property sheet it will have the following + properties customized: + - 'model' - will have a '...' button that will open a customized dialog for + editing the widget model (same has 'Edit model...' task menu item +""" + +from taurus.core.util.log import Logger +from taurus.qt import Qt +from taurus.qt import QtDesigner + +from taurus.qt.qtgui.container.qcontainer import QGroupWidget + +#import sip + +Q_TYPEID = {'QPyDesignerContainerExtension': 'com.trolltech.Qt.Designer.Container', + 'QPyDesignerPropertySheetExtension': 'com.trolltech.Qt.Designer.PropertySheet', + 'QPyDesignerTaskMenuExtension': 'com.trolltech.Qt.Designer.TaskMenu', + 'QPyDesignerMemberSheetExtension': 'com.trolltech.Qt.Designer.MemberSheet'} + + +class QGroupWidgetContainerExtension(QtDesigner.QPyDesignerContainerExtension): + def __init__(self, widget, parent=None): + super(QGroupWidgetContainerExtension, self).__init__(parent) + self._widget = widget + self._page_widget = None + + def addWidget(self, widget): + if self.count() > 0: + raise Exception("Can only have at maximum one child") + self._layout().addWidget(widget) + self._page_widget = widget + + def _content(self): + return self._widget.content() + + def _layout(self): + return self._content().layout() + + def count(self): + return self._layout().count() + + def currentIndex(self): + if self.count() > 0: + return 0 + return -1 + + def insertWidget(self, index, widget): + self.addWidget(widget) + + def remove(self, index): + self._layout().removeWidget(self.widget(index)) + + def setCurrentIndex(self, index): + pass + + def widget(self, index): + return self._page_widget + + +class QGroupWidgetExtensionFactory(QtDesigner.QExtensionFactory): + def __init__(self, parent=None): + super(QGroupWidgetExtensionFactory, self).__init__(parent) + + def createExtension(self, obj, iid, parent): + if iid != Q_TYPEID['QPyDesignerContainerExtension']: + return None + if isinstance(obj, QGroupWidget): + return QGroupWidgetContainerExtension(obj, parent) + return None + +def create_plugin(): + from taurusplugin.taurusplugin import TaurusWidgetPlugin + + class QGroupWidgetPlugin(TaurusWidgetPlugin): + + WidgetClass = QGroupWidget + + def initialize(self, formEditor): + if self.isInitialized(): + return + + manager = formEditor.extensionManager() + if manager: + self.factory = QGroupWidgetExtensionFactory(manager) + manager.registerExtensions(self.factory, Q_TYPEID['QPyDesignerContainerExtension']) + self.initialized = True + return QGroupWidgetPlugin + +QGroupWidgetPlugin = create_plugin() + + \ No newline at end of file diff -Nru taurus-3.0.0/lib/taurus/qt/qtdesigner/extraguiqwtplugin.py taurus-3.1.0/lib/taurus/qt/qtdesigner/extraguiqwtplugin.py --- taurus-3.0.0/lib/taurus/qt/qtdesigner/extraguiqwtplugin.py 2012-04-30 07:46:23.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtdesigner/extraguiqwtplugin.py 2013-07-25 07:53:15.000000000 +0000 @@ -27,11 +27,13 @@ guiqwt widgets plugins for Qt Designer """ -from guiqwt.qtdesigner import create_qtdesigner_plugin - -PlotPlugin = create_qtdesigner_plugin("guiqwt", "guiqwt.plot", "CurveWidget", - icon="curve.png") - -ImagePlotPlugin = create_qtdesigner_plugin("guiqwt", "guiqwt.plot", "ImageWidget", - icon="image.png") +try: + from guiqwt.qtdesigner import create_qtdesigner_plugin + PlotPlugin = create_qtdesigner_plugin("guiqwt", "guiqwt.plot", "CurveWidget", + icon="curve.png") + ImagePlotPlugin = create_qtdesigner_plugin("guiqwt", "guiqwt.plot", "ImageWidget", + icon="image.png") +except ImportError: + from taurus.core.util.log import debug + debug("failed to load guiqwt designer plugin") diff -Nru taurus-3.0.0/lib/taurus/qt/qtdesigner/taurusdesigner.py taurus-3.1.0/lib/taurus/qt/qtdesigner/taurusdesigner.py --- taurus-3.0.0/lib/taurus/qt/qtdesigner/taurusdesigner.py 1970-01-01 00:00:00.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtdesigner/taurusdesigner.py 2013-07-25 07:53:15.000000000 +0000 @@ -0,0 +1,143 @@ +#!/usr/bin/env python + +############################################################################# +## +## This file is part of Taurus, a Tango User Interface Library +## +## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html +## +## 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 . +## +############################################################################# + +import sys +import os.path +import optparse + +import taurus +from taurus.qt import Qt + +def env_index(env, env_name): + env_name = str(env_name) + for i, e in enumerate(env): + e = str(e) + if e.startswith(env_name): + return i + return -1 + +def has_env(env, env_name): + return env_index(env, env_name) != -1 + +def get_env(env, env_name): + env_name = str(env_name) + for i, e in enumerate(env): + e = str(e) + if e.startswith(env_name): + return e.split("=")[1] + return None + +def append_or_create_env(env, env_name, env_value, is_path_like=True): + i = env_index(env, env_name) + if i == -1: + env.append(env_name + "=" + env_value) + else: + if is_path_like: + e_n, e_v = env[i].split("=") + paths = e_v.split(os.path.pathsep) + if not env_value in paths: + env_value += os.path.pathsep + e_v + env[i] = env_name + "=" + env_value + +def append_or_create_env_list(env, env_name, env_value): + env_value = os.path.pathsep.join(env_value) + append_or_create_env(env, env_name, env_value) + +def get_qtdesigner_bin(): + designer_bin = str(Qt.QLibraryInfo.location(Qt.QLibraryInfo.BinariesPath)) + + plat = sys.platform + if plat == "darwin": + designer_bin = os.path.join(designer_bin, "Designer.app", "Contents", "MacOS") + elif plat in ("win32", "nt"): + import PyQt4 + designer_bin = os.path.abspath(os.path.dirname(PyQt4.__file__)) + + designer_bin = os.path.join(designer_bin, "designer") + return designer_bin + +def get_taurus_designer_path(): + """Returns a list of directories containing taurus designer plugins""" + # Set PYQTDESIGNERPATH to look inside taurus for designer plugins + taurus_path = os.path.dirname(os.path.abspath(taurus.__file__)) + taurus_qt_designer_path = os.path.join(taurus_path, 'qt', 'qtdesigner') + return [taurus_qt_designer_path] + +def qtdesigner_prepare_taurus(env=None, taurus_extra_path=None): + + # Tell Qt Designer where it can find the directory containing the plugins + if env is None: + env = Qt.QProcess.systemEnvironment() + + # Set PYQTDESIGNERPATH to look inside taurus for designer plugins + taurus_designer_path = get_taurus_designer_path() + + append_or_create_env_list(env, "PYQTDESIGNERPATH", taurus_designer_path) + + # Set TAURUSQTDESIGNERPATH + if taurus_extra_path is not None: + append_or_create_env(env, "TAURUSQTDESIGNERPATH", taurus_extra_path) + append_or_create_env(env, "PYTHONPATH", taurus_extra_path) + + #print "PYTHONPATH=%s" % get_env(env, "PYTHONPATH") + #print "PYQTDESIGNERPATH=%s" % get_env(env, "PYQTDESIGNERPATH") + return env + +def qtdesigner_start(args, env=None): + # Start Designer. + designer_bin = get_qtdesigner_bin() + + designer = Qt.QProcess() + designer.setProcessChannelMode(Qt.QProcess.ForwardedChannels) + designer.setEnvironment(env) + designer.start(designer_bin, args) + designer.waitForFinished(-1) + + return designer.exitCode() + +def main(env=None): + version = "taurusdesigner %s" % (taurus.Release.version) + usage = "Usage: %prog [options] " + description = "The Qt designer application customized for taurus" + parser = optparse.OptionParser(version=version, usage=usage, description=description) + parser.add_option("--taurus-path", dest="tauruspath", default="", + help="additional directories to look for taurus widgets") + parser.add_option("--qt-designer-path", dest="pyqtdesignerpath", default="", + help="additional directories to look for python qt widgets") + + options, args = parser.parse_args() + + taurus_extra_path = None + # Set TAURUSQTDESIGNERPATH + if len(options.tauruspath) > 0: + taurus_extra_path = options.tauruspath + + env = qtdesigner_prepare_taurus(env=env, taurus_extra_path=taurus_extra_path) + + sys.exit(qtdesigner_start(args, env=env)) + +if __name__ == "__main__": + main() + diff -Nru taurus-3.0.0/lib/taurus/qt/qtdesigner/taurusplugin/taurusplugin.py taurus-3.1.0/lib/taurus/qt/qtdesigner/taurusplugin/taurusplugin.py --- taurus-3.0.0/lib/taurus/qt/qtdesigner/taurusplugin/taurusplugin.py 2012-04-30 07:46:23.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtdesigner/taurusplugin/taurusplugin.py 2013-07-25 07:53:15.000000000 +0000 @@ -23,10 +23,6 @@ ## ############################################################################# -""" -taurusplugin.py: -""" - """ Every TaurusWidget should have the following Qt Designer extended capabilities: - Task menu: @@ -41,27 +37,23 @@ editing the widget model (same has 'Edit model...' task menu item """ -import os - from taurus.qt import Qt -from PyQt4 import QtDesigner +from taurus.qt import QtDesigner -import taurus.core -import taurus.core.util -import logging +from taurus.core.util.log import Logger def Q_TYPEID(class_name): """ Helper function to generate an IID for Qt. Returns a QString.""" return Qt.QString("com.trolltech.Qt.Designer.%s" % class_name) -designer_logger = taurus.core.util.Logger("QtDesigner") +designer_logger = Logger("PyQtDesigner") class TaurusWidgetPlugin(QtDesigner.QPyDesignerCustomWidgetPlugin): """TaurusWidgetPlugin""" def __init__(self, parent = None): QtDesigner.QPyDesignerCustomWidgetPlugin.__init__(self) - self._log = taurus.core.util.Logger(self._getWidgetClassName(), designer_logger) + self._log = Logger(self._getWidgetClassName(), designer_logger) self.initialized = False def initialize(self, formEditor): @@ -95,10 +87,10 @@ w = None return w - def getWidgetInfo(self, key): + def getWidgetInfo(self, key, dft=None): if not hasattr(self, '_widgetInfo'): self._widgetInfo = self.getWidgetClass().getQtDesignerPluginInfo() - return self._widgetInfo.get(key) + return self._widgetInfo.get(key, dft) # This method returns the name of the custom widget class that is provided # by this plugin. @@ -109,10 +101,7 @@ """ Returns the name of the group in Qt Designer's widget box that this widget belongs to. It returns 'Taurus Widgets'. Overwrite if want another group.""" - group = self.getWidgetInfo('group') - if group is None: - group = 'Taurus Widgets' - return group + return self.getWidgetInfo('group', 'Taurus Widgets') def getIconName(self): return self.getWidgetInfo('icon') @@ -149,9 +138,4 @@ return whatsthis def isContainer(self): - container = self.getWidgetInfo('container') - if container is None: - container = False - return container - - + return self.getWidgetInfo('container', False) diff -Nru taurus-3.0.0/lib/taurus/qt/qtdesigner/tauruspluginplugin.py taurus-3.1.0/lib/taurus/qt/qtdesigner/tauruspluginplugin.py --- taurus-3.0.0/lib/taurus/qt/qtdesigner/tauruspluginplugin.py 2012-04-30 07:46:23.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtdesigner/tauruspluginplugin.py 2013-07-25 07:53:15.000000000 +0000 @@ -27,10 +27,8 @@ tauruspluginplugin.py: """ -import os +from taurus.qt import QtDesigner -from taurus.qt import Qt -from PyQt4 import QtDesigner def build_qtdesigner_widget_plugin(klass): import taurusplugin @@ -41,28 +39,29 @@ Plugin.__name__ = klass.__name__ + "QtDesignerPlugin" return Plugin -_SKIP = ["QLogo"] +_SKIP = ["QLogo", "QGroupWidget", "TaurusGroupWidget"] _plugins = {} def main(): - import taurus - import taurus.core.util - import taurus.qt.qtgui.util - #taurus.setLogLevel(taurus.Debug) - _log = taurus.core.util.Logger(__name__) + from taurus import Manager + from taurus.core.util.log import Logger + from taurus.core.taurusbasetypes import OperationMode + from taurus.qt.qtgui.util import TaurusWidgetFactory + Logger.setLogLevel(Logger.Debug) + _log = Logger(__name__) - taurus.Manager().setOperationMode(taurus.core.OperationMode.OFFLINE) + Manager().setOperationMode(OperationMode.OFFLINE) try: - wf = taurus.qt.qtgui.util.TaurusWidgetFactory() + wf = TaurusWidgetFactory() klasses = wf.getWidgetClasses() ok_nb, skipped_nb, e1_nb, e2_nb, e3_nb, e4_nb = 0, 0, 0, 0, 0, 0 for widget_klass in klasses: name = widget_klass.__name__ - _log.debug("Processing %s" % name) + #_log.debug("Processing %s" % name) if name in _SKIP: - _log.debug("Skipped %s" % name) + #_log.debug("Skipped %s" % name) skipped_nb += 1 continue # if getQtDesignerPluginInfo does not exist, returns None or raises @@ -71,24 +70,24 @@ try: qt_info = widget_klass.getQtDesignerPluginInfo() if qt_info is None: - _log.debug("E1: Canceled %s (getQtDesignerPluginInfo)" % name) + #_log.debug("E1: Canceled %s (getQtDesignerPluginInfo)" % name) e1_nb += 1 cont = True except AttributeError: - _log.debug("E2: Canceled %s (widget doesn't have getQtDesignerPluginInfo())" % name) + #_log.debug("E2: Canceled %s (widget doesn't have getQtDesignerPluginInfo())" % name) e2_nb += 1 cont = True except Exception,e: - _log.debug("E3: Canceled %s (%s)" % (name, str(e))) + #_log.debug("E3: Canceled %s (%s)" % (name, str(e))) e3_nb += 1 cont = True if cont: continue for k in ('module', ): if not qt_info.has_key(k): - _log.debug("E4: Canceled %s (getQtDesignerPluginInfo doesn't have key %s)" % (name, k)) - e4_nb += 1 - cont=True + #_log.debug("E4: Canceled %s (getQtDesignerPluginInfo doesn't have key %s)" % (name, k)) + e4_nb += 1 + cont=True if cont: continue plugin_klass = build_qtdesigner_widget_plugin(widget_klass) @@ -97,14 +96,16 @@ _plugins[plugin_klass_name] = plugin_klass ok_nb += 1 - _log.debug("DONE processing %s" % name) + #_log.debug("DONE processing %s" % name) _log.info("Inpected %d widgets. %d (OK), %d (Skipped), %d (E1), %d (E2), %d (E3), %d(E4)" % (len(klasses), ok_nb, skipped_nb, e1_nb, e2_nb, e3_nb, e4_nb)) _log.info("E1: getQtDesignerPluginInfo() returns None") _log.info("E2: widget doesn't implement getQtDesignerPluginInfo()") _log.info("E3: getQtDesignerPluginInfo() throws exception") _log.info("E4: getQtDesignerPluginInfo() returns dictionary with missing key (probably 'module' key)") - except Exception, e: - print e + except Exception as e: + import traceback; traceback.print_exc() + #print e + class TaurusWidgets(QtDesigner.QPyDesignerCustomWidgetCollectionPlugin): diff -Nru taurus-3.0.0/lib/taurus/qt/qtgui/application/taurusapplication.py taurus-3.1.0/lib/taurus/qt/qtgui/application/taurusapplication.py --- taurus-3.0.0/lib/taurus/qt/qtgui/application/taurusapplication.py 2012-04-30 07:47:11.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtgui/application/taurusapplication.py 2013-07-25 07:53:38.000000000 +0000 @@ -3,28 +3,30 @@ ############################################################################# ## ## This file is part of Taurus, a Tango User Interface Library -## +## ## http://www.tango-controls.org/static/taurus/latest/doc/html/index.html ## ## 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 . ## ############################################################################# -"""This module provides the base :class:`taurus.qt.qtgui.application.TaurusApplication` -class.""" +"""This module provides the base +:class:`taurus.qt.qtgui.application.TaurusApplication` class.""" + +from __future__ import with_statement __all__ = ["TaurusApplication"] @@ -34,6 +36,7 @@ import sys import logging import optparse +import threading from taurus.qt import Qt @@ -42,11 +45,13 @@ class STD(Logger): - + + FlushWaterMark = 1000 + def __init__(self, name='', parent=None, format=None, std=None, pure_text=True): """The STD Logger constructor - + :param name: (str) the logger name (default is empty string) :param parent: (Logger) the parent logger or None if no parent exists (default is None) @@ -54,27 +59,31 @@ log format (default is None) :param std: std to forward write :param pure_text: if True, writes the 'message' parameter of the log - message in a separate line preserving the indentation + message in a separate line preserving the + indentation """ Logger.__init__(self, name=name, parent=parent, format=format) self.buffer = '' self.log_obj.propagate = False self.std = std - + def addLogHandler(self, handler): - """When called, set to use a private handler and DON'T send messages to - parent loggers (basically will act as an independent logging system - by itself) + """When called, set to use a private handler and DON'T send messages + to parent loggers (basically will act as an independent logging system + by itself) :param handler: new handler""" Logger.addLogHandler(self, handler) self.log_obj.propagate = not len(self.log_handlers) - + def write(self, msg): try: self.buffer += msg # while there is no new line, just accumulate the buffer - if msg and (msg[-1] == '\n' or msg.index('\n') >= 0): + msgl = len(msg) + if msgl > 0 and \ + (msg[-1] == '\n' or msg.index('\n') >= 0 or \ + msgl >= self.FlushWaterMark): self.flush() except ValueError: pass @@ -85,7 +94,7 @@ except: pass pass - + def flush(self): try: buff = self.buffer @@ -93,7 +102,8 @@ return #take the '\n' because the output is a list of strings, each to be #interpreted as a separate line in the client - if buff[-1] == '\n': buff = buff[:-1] + if buff[-1] == '\n': + buff = buff[:-1] if self.log_handlers: self.log(Logger.Console, '\n' + buff) self.buffer = "" @@ -108,75 +118,82 @@ class TaurusApplication(Qt.QApplication, Logger): """A QApplication that additionally parses the command line looking - for taurus options. This is done using the :mod:`taurus.core.util.argparse`. + for taurus options. This is done using the + :mod:`taurus.core.util.argparse`. To create a TaurusApplication object you should use the same parameters - as in QApplication. - + as in QApplication. + The optional keyword parameters: - app_name: (str) application name - app_version: (str) application version - org_name: (str) organization name - org_domain: (str) organization domain - - ...And at last the 'cmd_line_parser' which should be an instance of + + ...And at last the 'cmd_line_parser' which should be an instance of :class:`optparse.OptionParser`. Simple example:: import sys import taurus.qt.qtgui.application import taurus.qt.qtgui.display - + app = taurus.qt.qtgui.application.TaurusApplication() - + w = taurus.qt.qtgui.display.TaurusLabel() w.model = 'sys/tg_test/1/double_scalar' w.show() sys.exit(app.exec_()) - + A more complex example showing how to add options and a usage help:: - + import sys import taurus.core.util.argparse import taurus.qt.qtgui.application import taurus.qt.qtgui.display - + parser = taurus.core.util.argparse.get_taurus_parser() parser.usage = "%prog [options] " parser.add_option("--hello") - + app = taurus.qt.qtgui.application.TaurusApplication(cmd_line_parser=parser) args = app.get_command_line_args() if len(args) < 1: sys.stderr.write("Need to supply model attribute") sys.exit(1) - + w = taurus.qt.qtgui.display.TaurusLabel() w.model = args[1] w.show() sys.exit(app.exec_()) - - For more details on taurus command line parsing check + + For more details on taurus command line parsing check :mod:`taurus.core.util.argparse`. """ - + def __init__(self, *args, **kwargs): """The constructor. Parameters are the same as QApplication plus a keyword parameter: 'cmd_line_parser' which should be an instance of :class:`optparse.OptionParser`""" + + # lock to safely get singleton elements (like IPython taurus + # console app) + self._lock = threading.Lock() + if len(args) == 0: - args = ([],) + args = getattr(sys, 'argv', []), + parser=None app_name, app_version, org_name, org_domain = None, None, None, None - if kwargs.has_key('app_name'): + if 'app_name' in kwargs: app_name = kwargs.pop('app_name') - if kwargs.has_key('app_version'): + if 'app_version' in kwargs: app_version = kwargs.pop('app_version') - if kwargs.has_key('org_name'): + if 'org_name' in kwargs: org_name = kwargs.pop('org_name') - if kwargs.has_key('org_domain'): + if 'org_domain' in kwargs: org_domain = kwargs.pop('org_domain') - if kwargs.has_key('cmd_line_parser'): + if 'cmd_line_parser' in kwargs: parser = kwargs.pop('cmd_line_parser') try: @@ -186,6 +203,9 @@ Logger.__init__(self) + self._out = None + self._err = None + if app_name is not None: self.setApplicationName(app_name) if app_version is not None: @@ -195,9 +215,6 @@ if org_domain is not None: self.setOrganizationDomain(org_domain) - self._out = None - self._err = None - # if the constructor was called without a parser or with a parser that # doesn't contain version information and with an application # name and/or version, then add the --version capability @@ -211,19 +228,20 @@ parser.version = v parser._add_version_option() - p, opt, args = taurus.core.util.argparse.init_taurus_args(parser=parser) - + p, opt, args = \ + taurus.core.util.argparse.init_taurus_args(parser=parser, args=args[0][1:]) + self._cmd_line_parser = p self._cmd_line_options = opt self._cmd_line_args = args self.__registerQtLogger() self.__registerExtensions() self.__redirect_std() - + def __registerQtLogger(self): import taurus.qt.qtcore.util taurus.qt.qtcore.util.initTaurusQtLogger() - + def __registerExtensions(self): """Registers taurus Qt extensions""" try: @@ -246,8 +264,10 @@ sys.stdout = self._out self._err = STD(name="ERR", std=sys.stderr) sys.stderr = self._err - - def __buildLogFileName(self, prefix="/tmp", name=None): + + def __buildLogFileName(self, prefix=None, name=None): + if prefix is None: + prefix = os.path.expanduser('~/tmp') appName = str(self.applicationName()) if not appName: appName = os.path.splitext(os.path.basename(sys.argv[0]))[0] @@ -258,42 +278,42 @@ name = appName + '.log' fileName = os.path.join(dirName, name) return fileName - + def get_command_line_parser(self): - """Returns the :class:`optparse.OptionParser` used to parse the command - line parameters. - + """Returns the :class:`optparse.OptionParser` used to parse the + command line parameters. + :return: the parser used in the command line :rtype: :class:`optparse.OptionParser`""" return self._cmd_line_parser - + def get_command_line_options(self): """Returns the :class:`optparse.Option` that resulted from parsing the command line parameters. - + :return: the command line options :rtype: :class:`optparse.Option`""" return self._cmd_line_options - + def get_command_line_args(self): """Returns the list of arguments that resulted from parsing the command line parameters. - + :return: the command line arguments :rtype: list of strings""" return self._cmd_line_args - + def setTaurusStyle(self, styleName): """Sets taurus application style to the given style name - + :param styleName: the new style name to be applied :type styleName: str""" import taurus.qt.qtgui.style taurus.qt.qtgui.style.setTaurusStyle(styleName) - + def basicConfig(self, log_file_name=None, maxBytes=1E7, backupCount=5, with_gui_exc_handler=True): - + # prepare exception handler to report exceptions as error log messages # and to taurus message box (if with_gui is set) hook_to = None @@ -301,19 +321,18 @@ import taurus.qt.qtgui.dialog hook_to = taurus.qt.qtgui.dialog.TaurusExceptHookMessageBox() sys.excepthook = LogExceptHook(hook_to=hook_to) - + # create a file log handler try: if log_file_name is None: log_file_name = self.__buildLogFileName() f_h = logging.handlers.RotatingFileHandler(log_file_name, - maxBytes=maxBytes, - backupCount=backupCount) + maxBytes=maxBytes, backupCount=backupCount) Logger.addRootLogHandler(f_h) - if self._out is not None: + if self._out is not None: self._out.std = sys.__stdout__ self._out.addLogHandler(f_h) - if self._out is not None: + if self._out is not None: self._err.std = sys.__stderr__ self._err.addLogHandler(f_h) self.info("Logs will be saved in %s", log_file_name) @@ -321,4 +340,4 @@ self.warning("'%s' could not be created. Logs will not be stored", log_file_name) self.debug("Error description", exc_info=1) - + diff -Nru taurus-3.0.0/lib/taurus/qt/qtgui/base/taurusbase.py taurus-3.1.0/lib/taurus/qt/qtgui/base/taurusbase.py --- taurus-3.0.0/lib/taurus/qt/qtgui/base/taurusbase.py 2012-04-30 07:47:11.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtgui/base/taurusbase.py 2013-07-25 07:53:39.000000000 +0000 @@ -37,8 +37,14 @@ from taurus.qt import Qt -import taurus.core +import taurus from taurus.core.util import eventfilters +from taurus.core.taurusbasetypes import TaurusElementType, TaurusEventType +from taurus.core.taurusattribute import TaurusAttribute +from taurus.core.taurusdevice import TaurusDevice +from taurus.core.taurusconfiguration import TaurusConfiguration +from taurus.core.tauruslistener import TaurusListener, TaurusExceptionListener +from taurus.core.taurusoperation import WriteAttrOperation from taurus.qt.qtcore.configuration import BaseConfigurableClass from taurus.qt.qtcore.mimetypes import TAURUS_ATTR_MIME_TYPE, TAURUS_DEV_MIME_TYPE, TAURUS_MODEL_MIME_TYPE from taurus.qt.qtgui.util import ActionFactory @@ -78,7 +84,7 @@ PyTango.ArgType.DevVarUShortArray : 'QList', } -class TaurusBaseComponent(taurus.core.TaurusListener, BaseConfigurableClass): +class TaurusBaseComponent(TaurusListener, BaseConfigurableClass): """A generic Taurus component. .. note:: @@ -97,7 +103,7 @@ self.modelName = '' self.noneValue = DefaultNoneValue self._designMode = designMode - self.call__init__(taurus.core.TaurusListener, name, parent) + self.call__init__(TaurusListener, name, parent) BaseConfigurableClass.__init__(self) @@ -121,7 +127,7 @@ if parent != None and hasattr(parent, "_exception_listener"): self._exception_listener = parent._exception_listener else: - self._exception_listener = set([taurus.core.TaurusExceptionListener()]) + self._exception_listener = set([TaurusExceptionListener()]) #register configurable properties self.registerConfigProperty(self.isModifiableByUser, self.setModifiableByUser, "modifiableByUser") @@ -155,7 +161,7 @@ import taurus manager = taurus.Manager() - :return: (taurus.core.TaurusManager) the TaurusManager + :return: (taurus.core.taurusmanager.TaurusManager) the TaurusManager """ return taurus.Manager() @@ -168,7 +174,7 @@ :param scheme: (str or None) the scheme. None defaults to 'tango'. - :return: (taurus.core.TaurusFactory) the TaurusFactory + :return: (taurus.core.taurusfactory.TaurusFactory) the TaurusFactory """ return taurus.Factory(scheme) @@ -199,7 +205,7 @@ def getParentTaurusComponent(self): """ Returns a parent Taurus component or None if no parent - :class:`taurus.core.TaurusBaseComponent` is found. + :class:`taurus.qt.qtgui.base.TaurusBaseComponent` is found. :raises: RuntimeError """ @@ -227,7 +233,7 @@ (i.e. reimplementing :meth:`handleEvent`) :param evt_src: (object) object that triggered the event - :param evt_type: (taurus.core.TaurusEventType) type of event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType) type of event :param evt_value: (object) event value """ self.fireEvent(evt_src, evt_type, evt_value) @@ -240,7 +246,7 @@ or Qt threads, respectively :param evt_src: (object or None) object that triggered the event - :param evt_type: (taurus.core.TaurusEventType or None) type of event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType or None) type of event :param evt_value: (object or None) event value """ try: self.getSignaller().emit(Qt.SIGNAL('taurusEvent'), evt_src, evt_type, evt_value) @@ -251,7 +257,7 @@ unless one of them returns None (in which case the event is discarded) :param evt_src: (object) object that triggered the event - :param evt_type: (taurus.core.TaurusEventType) type of event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType) type of event :param evt_value: (object) event value """ r = evt_src, evt_type, evt_value @@ -276,7 +282,7 @@ Reimplement as necessary :param evt_src: (object or None) object that triggered the event - :param evt_type: (taurus.core.TaurusEventType or None) type of event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType or None) type of event :param evt_value: (object or None) event value """ pass @@ -298,7 +304,7 @@ value to be filtered as well. This can be done as in this example:: TaurusBaseComponent.fireEvent( TaurusBaseComponent.getModelObj(), - taurus.core.TaurusEventType.Periodic, + taurus.core.taurusbasetypes.TaurusEventType.Periodic, TaurusBaseComponent.getModelObj().getValueObj()) See also: insertEventFilter @@ -447,7 +453,7 @@ """Returns the parent model object or None if the component has no parent or if the parent's model is None - :return: (taurus.core.TaurusModel or None) the parent taurus model object + :return: (taurus.core.taurusmodel.TaurusModel or None) the parent taurus model object """ try: p = self.getParentTaurusComponent() @@ -461,19 +467,19 @@ """Returns the taurus model obj associated with this component or None if no taurus model is associated. - :return: (taurus.core.TaurusModel or None) the taurus model object + :return: (taurus.core.taurusmodel.TaurusModel or None) the taurus model object """ return self.modelObj def getModelType(self): """Returns the taurus model type associated with this component or - taurus.core.TaurusElementType.Unknown if no taurus model is associated. + taurus.core.taurusbasetypes.TaurusElementType.Unknown if no taurus model is associated. - :return: (taurus.core.TaurusElementType) the taurus model type + :return: (taurus.core.taurusbasetypes.TaurusElementType) the taurus model type """ model_obj = self.getModelObj() if model_obj is None: - return taurus.core.TaurusElementType.Unknown + return TaurusElementType.Unknown return model_obj.getTaurusElementType() def getModelValueObj(self,cache=True): @@ -677,7 +683,7 @@ self.changeLogName(new_log_name) self.modelObj = None self._attached = False - self.fireEvent(m, taurus.core.TaurusEventType.Change, None) + self.fireEvent(m, TaurusEventType.Change, None) self.postDetach() @@ -721,7 +727,7 @@ Use :meth:`TaurusBaseWidget.safeApplyOperation` if you want to warn the user before applying - :param ops: (sequence or None) list of operations to apply. + :param ops: (sequence or None) list of operations to apply. If None is given (default) the component fetches the pending operations """ self.debug("Apply changes") @@ -747,7 +753,7 @@ def getPendingOperations(self): """Returns the sequence of pending operations - :return: (sequence) a list of pending operations + :return: (sequence) a list of pending operations """ return self._operations @@ -835,8 +841,8 @@ self._localModelName = model # # if in offline mode don't bother trying to register -# opMode = taurus.core.TaurusManager().getOperationMode() -# if opMode == taurus.core.OperationMode.OFFLINE: +# opMode = taurus.core.taurusmanager.TaurusManager().getOperationMode() +# if opMode == taurus.core.taurusbasetypes.OperationMode.OFFLINE: # return parent_widget = None @@ -852,7 +858,7 @@ if self.getUseParentModel(): parent_widget = self.getParentTaurusComponent() self.setModelName(model, parent_widget) - #self.fireEvent(self.getModelObj(), taurus.core.TaurusEventType.Change, self.getModelValueObj()) + #self.fireEvent(self.getModelObj(), taurus.core.taurusbasetypes.TaurusEventType.Change, self.getModelValueObj()) def resetModel(self): """Sets the model name to the empty string""" @@ -913,7 +919,7 @@ if showText == self._showText: return self._showText = showText - self.fireEvent(self.getModelObj(),taurus.core.TaurusEventType.Change, self.getModelValueObj()) + self.fireEvent(self.getModelObj(), TaurusEventType.Change, self.getModelValueObj()) self.updateStyle() def getShowText(self): @@ -1147,19 +1153,19 @@ Override when necessary. :param evt_src: (object or None) object that triggered the event - :param evt_type: (taurus.core.TaurusEventType or None) type of event + :param evt_type: (taurus.core.taurusbasetypes.TaurusEventType or None) type of event :param evt_value: (object or None) event value """ #Update the text shown by the widget if self._setText: text = '' if self.getShowText(): - if isinstance(evt_src, taurus.core.TaurusAttribute): - if evt_type in (taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic): + if isinstance(evt_src, TaurusAttribute): + if evt_type in (TaurusEventType.Change, TaurusEventType.Periodic): text = self.displayValue(evt_value.value) - elif evt_type == taurus.core.TaurusEventType.Error: + elif evt_type == TaurusEventType.Error: text = self.getNoneValue() - elif evt_type == taurus.core.TaurusEventType.Config: + elif evt_type == TaurusEventType.Config: text = self.getDisplayValue() else: text = self.getDisplayValue() @@ -1316,9 +1322,9 @@ modelclass = self.getModelClass() except: return [] - if modelclass == taurus.core.TaurusDevice: + if modelclass == TaurusDevice: return [TAURUS_DEV_MIME_TYPE, TAURUS_MODEL_MIME_TYPE] - elif modelclass == taurus.core.TaurusAttribute: + elif modelclass == TaurusAttribute: return [TAURUS_ATTR_MIME_TYPE, TAURUS_MODEL_MIME_TYPE] else: return [TAURUS_MODEL_MIME_TYPE] @@ -1400,9 +1406,9 @@ modelclass = self.getModelClass() except: modelclass = None - if issubclass(modelclass, taurus.core.TaurusDevice): + if issubclass(modelclass, TaurusDevice): mimeData.setData(TAURUS_DEV_MIME_TYPE, modelname) - elif issubclass(modelclass, taurus.core.TaurusAttribute): + elif issubclass(modelclass, TaurusAttribute): mimeData.setData(TAURUS_ATTR_MIME_TYPE, modelname) return mimeData @@ -1463,7 +1469,7 @@ def safeApplyOperations(self, ops = None): """Applies the given operations (or the pending operations if None passed) - :param ops: (sequence or None) list of operations to apply. + :param ops: (sequence or None) list of operations to apply. If None is given (default) the component fetches the pending operations """ @@ -1557,7 +1563,7 @@ #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- def getModelClass(self): - return taurus.core.TaurusAttribute + return TaurusAttribute def isReadOnly(self): return False @@ -1613,8 +1619,8 @@ that pending operations are properly created, not calling this method''' try: v = self.getValue() - op = taurus.core.WriteAttrOperation(self.getModelObj(), v, - self.getOperationCallbacks()) + op = WriteAttrOperation(self.getModelObj(), v, + self.getOperationCallbacks()) op.setDangerMessage(self.getDangerMessage()) self.safeApplyOperations([op]) self.info('Force-Applied value = %s'%str(v)) @@ -1623,7 +1629,7 @@ self.traceback() def handleEvent(self, src, evt_type, evt_value): - if evt_type in (taurus.core.TaurusEventType.Change, taurus.core.TaurusEventType.Periodic): + if evt_type in (TaurusEventType.Change, TaurusEventType.Periodic): self.emitValueChanged() def postAttach(self): @@ -1657,8 +1663,8 @@ if model.areStrValuesEqual(model_value, wigdet_value): self._operations = [] else: - operation = taurus.core.WriteAttrOperation(model, wigdet_value, - self.getOperationCallbacks()) + operation = WriteAttrOperation(model, wigdet_value, + self.getOperationCallbacks()) operation.setDangerMessage(self.getDangerMessage()) self._operations = [operation] except: @@ -1690,15 +1696,15 @@ if isinstance(v, Qt.QIntValidator): bottom = evt_value.min_value top = evt_value.max_value - bottom = int(bottom) if bottom != taurus.core.TaurusConfiguration.no_min_value else -sys.maxint - top = int(top) if top != taurus.core.TaurusConfiguration.no_max_value else sys.maxint + bottom = int(bottom) if bottom != TaurusConfiguration.no_min_value else -sys.maxint + top = int(top) if top != TaurusConfiguration.no_max_value else sys.maxint v.setRange(bottom, top) self.debug("Validator range set to %i-%i"%(bottom,top)) elif isinstance(v, Qt.QDoubleValidator): bottom = evt_value.min_value top = evt_value.max_value - bottom = float(bottom) if bottom != taurus.core.TaurusConfiguration.no_min_value else -float("inf") - top = float(top) if top != taurus.core.TaurusConfiguration.no_max_value else float("inf") + bottom = float(bottom) if bottom != TaurusConfiguration.no_min_value else -float("inf") + top = float(top) if top != TaurusConfiguration.no_max_value else float("inf") v.setBottom(bottom) v.setTop(top) self.debug("Validator range set to %f-%f"%(bottom,top)) diff -Nru taurus-3.0.0/lib/taurus/qt/qtgui/base/tauruscontroller.py taurus-3.1.0/lib/taurus/qt/qtgui/base/tauruscontroller.py --- taurus-3.0.0/lib/taurus/qt/qtgui/base/tauruscontroller.py 2012-04-30 07:47:11.000000000 +0000 +++ taurus-3.1.0/lib/taurus/qt/qtgui/base/tauruscontroller.py 2013-07-25 07:53:39.000000000 +0000 @@ -37,7 +37,7 @@ from taurus.qt import Qt -from taurus.core import DataFormat, TaurusEventType +from taurus.core.taurusbasetypes import DataFormat, TaurusEventType from taurus.qt.qtgui.util import QT_ATTRIBUTE_QUALITY_PALETTE from taurus.qt.qtgui.util import QT_DEVICE_STATE_PALETTE @@ -105,24 +105,31 @@ return self.widget().getDisplayValue() def handleEvent(self, evt_src, evt_type, evt_value): - if evt_type == TaurusEventType.Change or evt_type == TaurusEventType.Periodic: - self._last_value = evt_value - elif evt_type == TaurusEventType.Config: - self._last_config_value = evt_value - else: - self._last_error_value = evt_value - #In case of error, modify the last_value as well - try: - self._last_value = self.modelObj().getValueObj() - except: - pass + if evt_src == self.modelObj(): #update the "_last" values only if the event source is the model (it could be the background...) + if evt_type == TaurusEventType.Change or evt_type == TaurusEventType.Periodic: + self._last_value = evt_value + elif evt_type == TaurusEventType.Config: + self._last_config_value = evt_value + else: + self._last_error_value = evt_value + #In case of error, modify the last_value as well + try: + self._last_value = self.modelObj().getValueObj() + except: + pass self.update() def eventReceived(self, evt_src, evt_type, evt_value): # should handle the state event here. Because this is invoked by a random # thread, we pass it to the widget, which will forward to the proper # thread - self.widget().eventReceived(evt_src, evt_type, evt_value) + + #@todo: sometimes we get this method called but self.widget() is None. Check why. + # For the moment I just protect it by substituting the following line by the ones after it + #self.widget().eventReceived(evt_src, evt_type, evt_value) + w = self.widget() + if w is not None: + w.eventReceived(evt_src, evt_type, evt_value) def update(self): widget = self.widget() @@ -250,7 +257,9 @@ if self._configParam is None: model = self.widget().model try: - self._configParam = model[model.rfind('=')+1:].lower() #@todo: !!This is assuming tango names.A regexp or a call to a validator should be used + #@todo: This works for tango, eval and epics configuration names but is not general. + #@todo: This should be done calling to the ConfigurationNameValidator + self._configParam = model[model.rfind('?configuration=')+15:].lower() except: self._configParam = '' return self._configParam @@ -269,14 +278,29 @@ val = widget.getNoneValue() except: pass - except: + except AttributeError: + if param: + val = str(param) + attr = self.attrObj() + if attr is not None: + val = val.replace('