diff options
Diffstat (limited to 'lib/taurus/core')
43 files changed, 267 insertions, 191 deletions
diff --git a/lib/taurus/core/epics/__init__.py b/lib/taurus/core/epics/__init__.py index b39cf4a2..1f8123a8 100644 --- a/lib/taurus/core/epics/__init__.py +++ b/lib/taurus/core/epics/__init__.py @@ -54,11 +54,11 @@ 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 ca:my:example + $> taurus form ca:my:example Similarly, you can combine epics attributes with attributes from other schemes:: - $> taurusform 'ca:my:example' 'tango:sys/tg_test/1/float_scalar'\ + $> taurus form 'ca:my:example' 'tango:sys/tg_test/1/float_scalar'\ 'eval:{ca:my:example}*{tango:sys/tg_test/1/float_scalar}' Currently, the taurus epics scheme just supports epics PVs, implementing them as diff --git a/lib/taurus/core/epics/epicsattribute.py b/lib/taurus/core/epics/epicsattribute.py index bba58f84..11680af2 100644 --- a/lib/taurus/core/epics/epicsattribute.py +++ b/lib/taurus/core/epics/epicsattribute.py @@ -226,14 +226,6 @@ class EpicsAttribute(TaurusAttribute): def isUsingEvents(self): return True # TODO: implement this - - def _subscribeEvents(self): - raise NotImplementedError("Not allowed to call AbstractClass" + - " TaurusAttribute._subscribeEvents") - - def _unsubscribeEvents(self): - raise NotImplementedError("Not allowed to call AbstractClass" + - " TaurusAttribute._unsubscribeEvents") # ------------------------------------------------------------------------------ def factory(self): diff --git a/lib/taurus/core/epics/test/test_epicsattribute.py b/lib/taurus/core/epics/test/test_epicsattribute.py index 3a32c91f..3a32c91f 100755..100644 --- a/lib/taurus/core/epics/test/test_epicsattribute.py +++ b/lib/taurus/core/epics/test/test_epicsattribute.py diff --git a/lib/taurus/core/evaluation/evalattribute.py b/lib/taurus/core/evaluation/evalattribute.py index f7277f2e..1e414519 100644 --- a/lib/taurus/core/evaluation/evalattribute.py +++ b/lib/taurus/core/evaluation/evalattribute.py @@ -445,12 +445,6 @@ class EvaluationAttribute(TaurusAttribute): v = self.read(cache=False) self.fireEvent(TaurusEventType.Periodic, v) - def _subscribeEvents(self): - pass - - def _unsubscribeEvents(self): - pass - def isUsingEvents(self): # if this attributes depends from others, then we consider it uses # events diff --git a/lib/taurus/core/evaluation/evalfactory.py b/lib/taurus/core/evaluation/evalfactory.py index f7bd6c5c..f7bd6c5c 100755..100644 --- a/lib/taurus/core/evaluation/evalfactory.py +++ b/lib/taurus/core/evaluation/evalfactory.py diff --git a/lib/taurus/core/evaluation/test/res/dev_example.py b/lib/taurus/core/evaluation/test/res/dev_example.py index cc093eb5..21ef55c7 100644 --- a/lib/taurus/core/evaluation/test/res/dev_example.py +++ b/lib/taurus/core/evaluation/test/res/dev_example.py @@ -81,7 +81,7 @@ def test2(): import sys from taurus.qt.qtgui.application import TaurusApplication from taurus.qt.qtgui.panel import TaurusForm - app = TaurusApplication() + app = TaurusApplication(cmd_line_parser=None) w = TaurusForm() attrname = 'eval:@taurus.core.evaluation.test.res.dev_example.FreeSpaceDevice/getFreeSpace("/")' diff --git a/lib/taurus/core/evaluation/test/res/ipap_example.py b/lib/taurus/core/evaluation/test/res/ipap_example.py index de47bbad..2e391459 100644 --- a/lib/taurus/core/evaluation/test/res/ipap_example.py +++ b/lib/taurus/core/evaluation/test/res/ipap_example.py @@ -44,7 +44,7 @@ def _test2(): import sys from taurus.qt.qtgui.application import TaurusApplication from taurus.qt.qtgui.display import TaurusLabel - app = TaurusApplication() + app = TaurusApplication(cmd_line_parser=None) tl = TaurusLabel() tl.setModel(ATTR_IPAP_POS) diff --git a/lib/taurus/core/evaluation/test/test_evalattribute.py b/lib/taurus/core/evaluation/test/test_evalattribute.py index 6e9a7388..6e9a7388 100755..100644 --- a/lib/taurus/core/evaluation/test/test_evalattribute.py +++ b/lib/taurus/core/evaluation/test/test_evalattribute.py diff --git a/lib/taurus/core/init_bkcomp.py b/lib/taurus/core/init_bkcomp.py index 26f64052..3a480733 100644 --- a/lib/taurus/core/init_bkcomp.py +++ b/lib/taurus/core/init_bkcomp.py @@ -42,6 +42,7 @@ from .taurusmanager import * from .taurusoperation import * from .tauruspollingtimer import * from .taurusvalidator import * +from .units import * # enable compatibility code with tau V1 if tauv1 package is present try: diff --git a/lib/taurus/core/release.py b/lib/taurus/core/release.py index 00dda8f6..820800f5 100644 --- a/lib/taurus/core/release.py +++ b/lib/taurus/core/release.py @@ -47,7 +47,7 @@ name = 'taurus' # we use semantic versioning (http://semver.org/) and we update it using the # bumpversion script (https://github.com/peritus/bumpversion) -version = '4.5.0' +version = '4.6.1' # generate version_info and revision (**deprecated** since version 4.0.2-dev). if '-' in version: diff --git a/lib/taurus/core/resource/resvalidator.py b/lib/taurus/core/resource/resvalidator.py index 6e3e99a6..581ededd 100644 --- a/lib/taurus/core/resource/resvalidator.py +++ b/lib/taurus/core/resource/resvalidator.py @@ -29,8 +29,8 @@ from taurus.core.taurusvalidator import (TaurusAttributeNameValidator, TaurusAuthorityNameValidator) from taurus.core.taurushelper import getSchemeFromName, Factory -__all__ = ['ResDeviceNameValidator', - 'ResAttributeNameValidator'] +__all__ = ['ResourceAuthorityNameValidator', 'ResourceDeviceNameValidator', + 'ResourceAttributeNameValidator'] # Pattern for python variables PY_VAR = r'(?<![\.a-zA-Z0-9_])[a-zA-Z_][a-zA-Z0-9_]*' diff --git a/lib/taurus/core/resource/test/res/__init__.py b/lib/taurus/core/resource/test/res/__init__.py index e69de29b..e69de29b 100755..100644 --- a/lib/taurus/core/resource/test/res/__init__.py +++ b/lib/taurus/core/resource/test/res/__init__.py diff --git a/lib/taurus/core/resource/test/res/attr_resources_file.py b/lib/taurus/core/resource/test/res/attr_resources_file.py index 0db7a6e0..0db7a6e0 100755..100644 --- a/lib/taurus/core/resource/test/res/attr_resources_file.py +++ b/lib/taurus/core/resource/test/res/attr_resources_file.py diff --git a/lib/taurus/core/resource/test/test_resfactory.py b/lib/taurus/core/resource/test/test_resfactory.py index e80714a4..e80714a4 100755..100644 --- a/lib/taurus/core/resource/test/test_resfactory.py +++ b/lib/taurus/core/resource/test/test_resfactory.py diff --git a/lib/taurus/core/resource/test/test_resvalidator.py b/lib/taurus/core/resource/test/test_resvalidator.py index 4384e97b..4384e97b 100755..100644 --- a/lib/taurus/core/resource/test/test_resvalidator.py +++ b/lib/taurus/core/resource/test/test_resvalidator.py diff --git a/lib/taurus/core/tango/tangoattribute.py b/lib/taurus/core/tango/tangoattribute.py index 9bd9af00..b0620881 100755..100644 --- a/lib/taurus/core/tango/tangoattribute.py +++ b/lib/taurus/core/tango/tangoattribute.py @@ -119,8 +119,10 @@ class TangoAttrValue(TaurusAttrValue): for _ in range(len(shape) - 1): p.value = [p.value] - rvalue = p.value - wvalue = p.w_value + # Protect against DeviceAttribute not providing .value in some cases, + # seen e.g. in PyTango 9.3.0 + rvalue = getattr(p, 'value', None) + wvalue = getattr(p, 'w_value', None) if numerical: units = self._attrRef._units if rvalue is not None: @@ -324,6 +326,7 @@ class TangoAttribute(TaurusAttribute): def cleanUp(self): self.trace("[TangoAttribute] cleanUp") self._unsubscribeConfEvents() + self._unsubscribeChangeEvents() TaurusAttribute.cleanUp(self) self.__dev_hw_obj = None self._pytango_attrinfoex = None @@ -417,7 +420,7 @@ class TangoAttribute(TaurusAttribute): elif fmt in (DataFormat._1D, DataFormat._2D): if PyTango.is_int_type(tgtype): # cast to integer because the magnitude conversion gives floats - attrvalue = magnitude.astype('int64') + attrvalue = numpy.array(magnitude, copy=False, dtype='int64') elif tgtype == PyTango.CmdArgType.DevUChar: attrvalue = magnitude.view('uint8') else: @@ -600,7 +603,7 @@ class TangoAttribute(TaurusAttribute): assert len(listeners) >= 1 if self.__subscription_state == SubscriptionState.Unsubscribed and len(listeners) == 1: - self._subscribeEvents() + self._subscribeChangeEvents() # if initial_subscription_state == SubscriptionState.Subscribed: if (len(listeners) > 1 @@ -630,7 +633,7 @@ class TangoAttribute(TaurusAttribute): return ret if self.__subscription_state != SubscriptionState.Unsubscribed: - self._unsubscribeEvents() + self._unsubscribeChangeEvents() return ret @@ -654,7 +657,7 @@ class TangoAttribute(TaurusAttribute): def _process_event_exception(self, ex): pass - def _subscribeEvents(self): + def _subscribeChangeEvents(self): """ Enable subscription to the attribute events. If change events are not supported polling is activated """ @@ -705,7 +708,7 @@ class TangoAttribute(TaurusAttribute): return self.__chg_evt_id - def _unsubscribeEvents(self): + def _unsubscribeChangeEvents(self): # Careful in this method: This is intended to be executed in the cleanUp # so we should not access external objects from the factory, like the # parent object diff --git a/lib/taurus/core/tango/tangodatabase.py b/lib/taurus/core/tango/tangodatabase.py index 0d29365b..cb138566 100644 --- a/lib/taurus/core/tango/tangodatabase.py +++ b/lib/taurus/core/tango/tangodatabase.py @@ -643,21 +643,22 @@ def get_env_var(env_var_name): if not os.path.exists(fname): return None - for line in file(fname): - strippedline = line.split('#', 1)[0].strip() - - if not strippedline: - # empty line - continue - - tup = strippedline.split('=', 1) - if len(tup) != 2: - # illegal line! - continue - - key, val = list(map(str.strip, tup)) - if key == env_var_name: - return val + with open(fname) as f: + for line in f: + strippedline = line.split('#', 1)[0].strip() + + if not strippedline: + # empty line + continue + + tup = strippedline.split('=', 1) + if len(tup) != 2: + # illegal line! + continue + + key, val = list(map(str.strip, tup)) + if key == env_var_name: + return val class TangoAuthority(TaurusAuthority): diff --git a/lib/taurus/core/tango/tangodevice.py b/lib/taurus/core/tango/tangodevice.py index 562faa66..60e979c8 100755..100644 --- a/lib/taurus/core/tango/tangodevice.py +++ b/lib/taurus/core/tango/tangodevice.py @@ -75,7 +75,7 @@ class TangoDevice(TaurusDevice): # This way we can call for example read_attribute on an object of this # class def __getattr__(self, name): - if self._deviceObj is not None: + if name != "_deviceObj" 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)) diff --git a/lib/taurus/core/tango/test/test_tangofactory.py b/lib/taurus/core/tango/test/test_tangofactory.py index 7c7c3a8a..7c7c3a8a 100755..100644 --- a/lib/taurus/core/tango/test/test_tangofactory.py +++ b/lib/taurus/core/tango/test/test_tangofactory.py diff --git a/lib/taurus/core/tango/util/formatter.py b/lib/taurus/core/tango/util/formatter.py index ce5ebd0d..ce5ebd0d 100755..100644 --- a/lib/taurus/core/tango/util/formatter.py +++ b/lib/taurus/core/tango/util/formatter.py diff --git a/lib/taurus/core/taurusattribute.py b/lib/taurus/core/taurusattribute.py index 9f61d5e1..eba0365a 100644 --- a/lib/taurus/core/taurusattribute.py +++ b/lib/taurus/core/taurusattribute.py @@ -79,7 +79,11 @@ class TaurusAttribute(TaurusModel): def cleanUp(self): self.trace("[TaurusAttribute] cleanUp") - self._unsubscribeEvents() + if hasattr(self, '_unsuscribeEvents'): + self.deprecated( + dep='TaurusAttribute._unsuscribeEvents API', + alt='If you need it called in cleanUp, re-implement cleanUp') + self._unsuscribeEvents() TaurusModel.cleanUp(self) #-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- @@ -146,14 +150,6 @@ class TaurusAttribute(TaurusModel): raise NotImplementedError("Not allowed to call AbstractClass" + " TaurusAttribute.poll") - def _subscribeEvents(self): - raise NotImplementedError("Not allowed to call AbstractClass" + - " TaurusAttribute._subscribeEvents") - - def _unsubscribeEvents(self): - raise NotImplementedError("Not allowed to call AbstractClass" + - " TaurusAttribute._unsubscribeEvents") - def isUsingEvents(self): raise NotImplementedError("Not allowed to call AbstractClass" + " TaurusAttribute.isUsingEvents") diff --git a/lib/taurus/core/taurusdevice.py b/lib/taurus/core/taurusdevice.py index ae605e1f..ae605e1f 100755..100644 --- a/lib/taurus/core/taurusdevice.py +++ b/lib/taurus/core/taurusdevice.py diff --git a/lib/taurus/core/taurusfactory.py b/lib/taurus/core/taurusfactory.py index 01a48148..230c2151 100644 --- a/lib/taurus/core/taurusfactory.py +++ b/lib/taurus/core/taurusfactory.py @@ -396,6 +396,17 @@ class TaurusFactory(object): ret.append(TaurusElementType.Authority) return ret + def getValidatorFromName(self, name): + """ + Obtain the validator object corresponding to the given model + name. If the model name is not valid for any TaurusModel class, + it returns None + """ + modeltypes = self.getValidTypesForName(name) + if not modeltypes: + return None + return self.elementTypesMap[modeltypes[0]].getNameValidator() + def findObjectClass(self, absolute_name): """ Obtain the class object corresponding to the given name. diff --git a/lib/taurus/core/taurushelper.py b/lib/taurus/core/taurushelper.py index a6de167b..07fb7d32 100644 --- a/lib/taurus/core/taurushelper.py +++ b/lib/taurus/core/taurushelper.py @@ -42,7 +42,8 @@ __all__ = ['check_dependencies', 'log_dependencies', 'getSchemeFromName', 'resetLogLevel', 'resetLogFormat', 'enableLogOutput', 'disableLogOutput', 'log', 'trace', 'debug', 'info', 'warning', 'error', 'fatal', - 'critical', 'deprecated', 'changeDefaultPollingPeriod'] + 'critical', 'deprecated', 'changeDefaultPollingPeriod', + 'getValidatorFromName'] __docformat__ = "restructuredtext" @@ -134,6 +135,21 @@ def getSchemeFromName(name, implicit=True): return None +def getValidatorFromName(name): + """Helper for obtaining the validator object corresponding to the + given name. + + :return: model name validator or None if name is not a supported model name + """ + + try: + factory = Factory(scheme=getSchemeFromName(name)) + except: + return None + return factory.getValidatorFromName(name) + + + def makeSchemeExplicit(name, default=None): """return the name guaranteeing that the scheme is present. If name already contains the scheme, it is returned unchanged. @@ -200,7 +216,7 @@ def isValidName(name, etypes=None, strict=None): for e in etypes: if e in validtypes: return True - return False + return False def Manager(): diff --git a/lib/taurus/core/taurusmanager.py b/lib/taurus/core/taurusmanager.py index 5ef57107..5ef57107 100755..100644 --- a/lib/taurus/core/taurusmanager.py +++ b/lib/taurus/core/taurusmanager.py diff --git a/lib/taurus/core/test/test_taurushelper.py b/lib/taurus/core/test/test_taurushelper.py index 252471ba..5febe0a7 100644 --- a/lib/taurus/core/test/test_taurushelper.py +++ b/lib/taurus/core/test/test_taurushelper.py @@ -466,5 +466,19 @@ class AttributeTestCase(unittest.TestCase): self.assertTrue(chk, msg) +class ValidatorFromName(unittest.TestCase): + """TestCase for the taurus.getValidatorFromName helper""" + + def test_getValidatorFromName(self): + """check that getValidatorFromName returns the expected values""" + + self.assertIsInstance( + taurus.getValidatorFromName('eval:@foo'), + taurus.core.evaluation.evalvalidator.EvaluationDeviceNameValidator + ) + self.assertIsNone(taurus.getValidatorFromName('eval:@/')) + self.assertIsNone(taurus.getValidatorFromName('unsupported:scheme')) + + if __name__ == '__main__': pass diff --git a/lib/taurus/core/units.py b/lib/taurus/core/units.py index 0d6ad349..64a1250e 100644 --- a/lib/taurus/core/units.py +++ b/lib/taurus/core/units.py @@ -27,6 +27,7 @@ This module provides a pint unit registry instance (`UR`) to be used by all taurus objects. It also provides the `Quantity` factory from that registry (also aliased as `Q_`). """ +__all__ = ['UR', 'Quantity', 'Q_'] from pint import UnitRegistry diff --git a/lib/taurus/core/util/argparse/taurusargparse.py b/lib/taurus/core/util/argparse/taurusargparse.py index b21e717a..4555f019 100644 --- a/lib/taurus/core/util/argparse/taurusargparse.py +++ b/lib/taurus/core/util/argparse/taurusargparse.py @@ -84,6 +84,12 @@ __all__ = ["get_taurus_parser", "init_taurus_args", "parse_taurus_args", __docformat__ = "restructuredtext" +from taurus.core.util import log as __log + +__log.deprecated(dep='taurus.core.util.argparse', rel='4.5.4', + alt='argparse or (better) click') + + def get_taurus_parser(parser=None): """ Returns a :class:`optparse.OptionParser` initialized with a :class:`optparse.OptionGroup` containning some taurus options. diff --git a/lib/taurus/core/util/codecs.py b/lib/taurus/core/util/codecs.py index 0b91df54..15cdd0ee 100644 --- a/lib/taurus/core/util/codecs.py +++ b/lib/taurus/core/util/codecs.py @@ -63,7 +63,7 @@ A Taurus related example:: >>> f, d = codec.decode((v.format, v.value)) """ from __future__ import absolute_import -from builtins import str +from builtins import str, bytes import copy @@ -79,7 +79,8 @@ from .log import Logger from .containers import CaselessDict __all__ = ["Codec", "NullCodec", "ZIPCodec", "BZ2Codec", "JSONCodec", - "FunctionCodec", "PlotCodec", "CodecPipeline", "CodecFactory"] + "Utf8Codec", "FunctionCodec", "PlotCodec", "CodecPipeline", + "CodecFactory"] __docformat__ = "restructuredtext" @@ -171,7 +172,7 @@ class ZIPCodec(Codec): 'Hello world\\nHello wo'""" def encode(self, data, *args, **kwargs): - """encodes the given data to a gzip string. The given data **must** be a string + """encodes the given data to gzip bytes. The given data **must** be bytes :param data: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object @@ -183,7 +184,7 @@ class ZIPCodec(Codec): return format, zlib.compress(data[1]) def decode(self, data, *args, **kwargs): - """decodes the given data from a gzip string. + """decodes the given data from a gzip bytes. :param data: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object @@ -214,7 +215,7 @@ class BZ2Codec(Codec): 'Hello world\\nHello wo'""" def encode(self, data, *args, **kwargs): - """encodes the given data to a bz2 string. The given data **must** be a string + """encodes the given data to bz2 bytes. The given data **must** be bytes :param data: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object @@ -226,7 +227,7 @@ class BZ2Codec(Codec): return format, bz2.compress(data[1]) def decode(self, data, *args, **kwargs): - """decodes the given data from a bz2 string. + """decodes the given data from bz2 bytes. :param data: (sequence[str, obj]) a sequence of two elements where the first item is the encoding format of the second item object @@ -259,7 +260,7 @@ class PickleCodec(Codec): {'hello': 'world', 'goodbye': 1000}""" def encode(self, data, *args, **kwargs): - """encodes the given data to a pickle string. The given data **must** be + """encodes the given data to pickle bytes. The given data **must** be a python object that :mod:`pickle` is able to convert. :param data: (sequence[str, obj]) a sequence of two elements where the @@ -331,7 +332,7 @@ class JSONCodec(Codec): format += '_%s' % data[0] # make it compact by default kwargs['separators'] = kwargs.get('separators', (',', ':')) - return format, json.dumps(data[1], *args, **kwargs).encode('utf-8') + return format, json.dumps(data[1], *args, **kwargs) def decode(self, data, *args, **kwargs): """decodes the given data from a json string. @@ -350,8 +351,6 @@ class JSONCodec(Codec): if isinstance(data[1], buffer_types): data = data[0], str(data[1]) - elif isinstance(data[1], bytes): - data = data[0], data[1].decode('utf-8') data = json.loads(data[1]) if ensure_ascii: @@ -380,6 +379,56 @@ class JSONCodec(Codec): return newdict +class Utf8Codec(Codec): + """A codec able to encode/decode utf8 strings to/from bytes. + Useful to adapt i/o encodings in a codec pipe. + + Example:: + + >>> from taurus.core.util.codecs import CodecFactory + + >>> cf = CodecFactory() + >>> codec = cf.getCodec('zip_utf8_json') + >>> + >>> # first encode something + >>> data = { 'hello' : 'world', 'goodbye' : 1000 } + >>> format, encoded_data = codec.encode(("", data)) + >>> + >>> # now decode it + >>> _, decoded_data = codec.decode((format, encoded_data)) + >>> print decoded_data + """ + + def encode(self, data, *args, **kwargs): + """ + Encodes the given utf8 string to bytes. + + :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 = 'utf8' + fmt, data = data + if len(fmt): + format += '_%s' % fmt + return format, str(data).encode() + + def decode(self, data, *args, **kwargs): + """decodes the given data from a bytes. + + :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 + """ + fmt, data = data + fmt = fmt.partition('_')[2] + return fmt, bytes(data).decode() + + class BSONCodec(Codec): """A codec able to encode/decode to/from bson format. It uses the :mod:`bson` module. @@ -550,7 +599,19 @@ class VideoImageCodec(Codec): imgBuffer = data[1][struct.calcsize(self.VIDEO_HEADER_FORMAT):] dtype = self.__getDtypeId(header['imageMode']) - if header['imageMode'] == 7: + + if header['imageMode'] == 6: + # RGB24, 3 bytes per pixel + rgba = numpy.fromstring(imgBuffer, dtype) + bbuf = rgba[0::3] + gbuf = rgba[1::3] + rbuf = rgba[2::3] + r = rbuf.reshape(header['height'], header['width']) + g = gbuf.reshape(header['height'], header['width']) + b = bbuf.reshape(header['height'], header['width']) + img2D = numpy.dstack((r, g, b)) + + elif header['imageMode'] == 7: # RGBA 4 bytes per pixel rgba = numpy.fromstring(imgBuffer, dtype) bbuf = rgba[0::4] @@ -698,7 +759,7 @@ class VideoImageCodec(Codec): # TODO: other modes #'RGB555' : 4,#Core.RGB555, #'RGB565' : 5,#Core.RGB565, - #'RGB24' : 6,#Core.RGB24, + 'RGB24': 6, # Core.RGB24, 'RGB32': 7, # Core.RGB32, #'BGR24' : 8,#Core.BGR24, #'BGR32' : 9,#Core.BGR32, @@ -719,7 +780,7 @@ class VideoImageCodec(Codec): 3: 'L', #'RGB555' : Core.RGB555, #'RGB565' : Core.RGB565, - #'RGB24' : Core.RGB24, + 6: 'RGB24', # Core.RGB24, 7: 'RGB32', # Core.RGB32, # 8 : 'BGR24',#Core.BGR24, #'BGR32' : Core.BGR32, @@ -740,7 +801,7 @@ class VideoImageCodec(Codec): 3: 'uint64', #'RGB555' : Core.RGB555, #'RGB565' : Core.RGB565, - # 6 : 'uint8', # Core.RGB24, + 6: 'uint8', # Core.RGB24, 7: 'uint8', # Core.RGB32, #'BGR24' : Core.BGR24, #'BGR32' : Core.BGR32, @@ -854,6 +915,7 @@ class CodecFactory(Singleton, Logger): #: Default minimum map of registered codecs CODEC_MAP = CaselessDict({ 'json': JSONCodec, + 'utf8': Utf8Codec, 'bson': BSONCodec, 'bz2': BZ2Codec, 'zip': ZIPCodec, diff --git a/lib/taurus/core/util/console.py b/lib/taurus/core/util/console.py index 051f721d..7ffe55c5 100644 --- a/lib/taurus/core/util/console.py +++ b/lib/taurus/core/util/console.py @@ -34,8 +34,7 @@ __docformat__ = "restructuredtext" def make_color_table(in_class, use_name=False, fake=False): """Build a set of color attributes in a class. - - Helper function for building the *TermColors classes.""" + Helper function for building the TermColors classes.""" color_templates = ( ("Black", "0;30"), ("Red", "0;31"), diff --git a/lib/taurus/core/util/constant.py b/lib/taurus/core/util/constant.py index c793322e..ae217333 100644 --- a/lib/taurus/core/util/constant.py +++ b/lib/taurus/core/util/constant.py @@ -69,5 +69,7 @@ class _consttype(object): def __del__(self): self.__dict__.clear() -import sys -sys.modules[__name__] = _consttype() + +if __name__ == '__main__': + import sys + sys.modules[__name__] = _consttype() diff --git a/lib/taurus/core/util/containers.py b/lib/taurus/core/util/containers.py index bbc8d762..8fbd5ce6 100644 --- a/lib/taurus/core/util/containers.py +++ b/lib/taurus/core/util/containers.py @@ -498,6 +498,8 @@ class LoopList(object): self._index += 1 return self.current() + next = __next__ + def previous(self): '''goes one item back in the list and returns it''' self._index -= 1 diff --git a/lib/taurus/core/util/decorator/__init__.py b/lib/taurus/core/util/decorator/__init__.py index e69de29b..2ff6c9a0 100644 --- a/lib/taurus/core/util/decorator/__init__.py +++ b/lib/taurus/core/util/decorator/__init__.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +############################################################################# +## +# This file is part of Taurus +## +# http://taurus-scada.org +## +# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain +## +# Taurus is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +## +# Taurus is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +## +# You should have received a copy of the GNU Lesser General Public License +# along with Taurus. If not, see <http://www.gnu.org/licenses/>. +## +############################################################################# + +""" +This module provides a few convenience decorators +"""
\ No newline at end of file diff --git a/lib/taurus/core/util/decorator/decorator.py b/lib/taurus/core/util/decorator/decorator.py index e26227f1..a3fef8af 100644 --- a/lib/taurus/core/util/decorator/decorator.py +++ b/lib/taurus/core/util/decorator/decorator.py @@ -23,36 +23,10 @@ ## ############################################################################# -"""\ -Allow to use decorator either with arguments or not. Example:: - - @decorator - def apply(func, *args, **kw): - return func(*args, **kw) - - @decorator - class apply: - def __init__(self, *args, **kw): - self.args = args - self.kw = kw - - def __call__(self, func): - return func(*self.args, **self.kw) - - # - # Usage in both cases: - # - @apply - def test(): - return 'test' - - assert test == 'test' - - @apply(2, 3) - def test(a, b): - return a + b - - assert test == 5""" +""" +Provides a decorator to decorate decorators so that they can be used both +with and without args +""" __all__ = ["decorator"] @@ -63,7 +37,8 @@ import inspect def decorator(func): - """Allow to use decorator either with arguments or not. Example:: + """ + Allow to use decorator either with arguments or not. Example:: @decorator def apply(func, *args, **kw): @@ -92,6 +67,7 @@ def decorator(func): return a + b assert test == 5 + """ def isFuncArg(*args, **kw): diff --git a/lib/taurus/core/util/decorator/typecheck.py b/lib/taurus/core/util/decorator/typecheck.py index 88ec269e..1b015e35 100644 --- a/lib/taurus/core/util/decorator/typecheck.py +++ b/lib/taurus/core/util/decorator/typecheck.py @@ -26,12 +26,15 @@ """ One of three degrees of enforcement may be specified by passing the 'debug' keyword argument to the decorator: - 0 -- NONE: No type-checking. Decorators disabled. - 1 -- MEDIUM: Print warning message to stderr. (Default) - 2 -- STRONG: Raise TypeError with message. + + - 0 -- NONE: No type-checking. Decorators disabled. + - 1 -- MEDIUM: Print warning message to stderr. (Default) + - 2 -- STRONG: Raise TypeError with message. + If 'debug' is not passed to the decorator, the default level is used. -Example usage: +Example usage:: + >>> NONE, MEDIUM, STRONG = 0, 1, 2 >>> >>> @accepts(int, int, int) @@ -47,7 +50,7 @@ Example usage: TypeWarning: 'average' method returns (float), but result is (int) 15 -Needed to cast params as floats in function def (or simply divide by 2.0). +Needed to cast params as floats in function def (or simply divide by 2.0):: >>> TYPE_CHECK = STRONG >>> @accepts(int, debug=TYPE_CHECK) @@ -71,15 +74,12 @@ __all__ = ["accepts", "returns"] __docformat__ = "restructuredtext" def accepts(*types, **kw): - """ Function decorator. Checks that inputs given to decorated function + """ + Function decorator. Checks that inputs given to decorated function are of the expected type. - Parameters: - types -- The expected types of the inputs to the decorated function. - Must specify type for each parameter. - kw -- Optional specification of 'debug' level (this is the only valid - keyword argument, no other should be given). - debug = ( 0 | 1 | 2 ) + :param types: The expected type of the decorated function's return value + :param debug: Optional specification of 'debug' level (0 | 1 | 2) """ if not kw: @@ -111,15 +111,12 @@ def accepts(*types, **kw): def returns(ret_type, **kw): - """ Function decorator. Checks that return value of decorated function + """ + Function decorator. Checks that return value of decorated function is of the expected type. - Parameters: - ret_type -- The expected type of the decorated function's return value. - Must specify type for each parameter. - kw -- Optional specification of 'debug' level (this is the only valid - keyword argument, no other should be given). - debug=(0 | 1 | 2) + :param ret_type: The expected type of the decorated function's return value. + :param debug: Optional specification of 'debug' level (0 | 1 | 2) """ try: diff --git a/lib/taurus/core/util/event.py b/lib/taurus/core/util/event.py index d2e67449..e77f6f20 100644 --- a/lib/taurus/core/util/event.py +++ b/lib/taurus/core/util/event.py @@ -106,7 +106,8 @@ def CallableRef(object, del_cb=None): :type del_cb: callable object or None :return: a weak reference for the given callable - :rtype: BoundMethodWeakref or weakref.ref""" + :rtype: taurus.core.util.BoundMethodWeakref or weakref.ref + """ im_self = None if hasattr(object, '__self__'): im_self = object.__self__ diff --git a/lib/taurus/core/util/parse_args.py b/lib/taurus/core/util/parse_args.py index 3da75c67..034c4abb 100644 --- a/lib/taurus/core/util/parse_args.py +++ b/lib/taurus/core/util/parse_args.py @@ -33,10 +33,10 @@ def parse_args(s, strip_pars=False): corresponding args and kwargs. :param s: string representing arguments to a method - :type strip_pars: (bool) If True, expect s to include surrounding - parenthesis + :param strip_pars: (bool) If True, expect s to include surrounding + parenthesis :return: args, kwargs (a list of positional arguments and a dict of keyword - arguments) + arguments) """ s = s.strip() if strip_pars: diff --git a/lib/taurus/core/util/property_parser.py b/lib/taurus/core/util/property_parser.py index 784055c2..4b981b21 100644 --- a/lib/taurus/core/util/property_parser.py +++ b/lib/taurus/core/util/property_parser.py @@ -101,7 +101,7 @@ def t_STRING(t): def t_KEY(t): - r'[a-zA-Z0-9_\.\/]+' + r'[a-zA-Z0-9/_\.\/]+' t.type = reserved.get(t.value, 'KEY') # Check for reserved words return t diff --git a/lib/taurus/core/util/propertyfile.py b/lib/taurus/core/util/propertyfile.py index a608b884..91182aaf 100644 --- a/lib/taurus/core/util/propertyfile.py +++ b/lib/taurus/core/util/propertyfile.py @@ -246,9 +246,6 @@ class Properties(object): def load(self, stream): """ Load properties from an open file stream """ - # For the time being only accept file input streams - if type(stream) is not file: - raise TypeError('Argument should be a file object!') # Check for the opened mode if stream.mode != 'r': raise ValueError('Stream should be opened in read-only mode!') diff --git a/lib/taurus/core/util/remotelogmonitor.py b/lib/taurus/core/util/remotelogmonitor.py index 9b7988be..9fbf673f 100644 --- a/lib/taurus/core/util/remotelogmonitor.py +++ b/lib/taurus/core/util/remotelogmonitor.py @@ -38,6 +38,7 @@ import logging import logging.handlers import struct import weakref +import click import socketserver @@ -181,47 +182,26 @@ def log(host, port, name=None, level=None): 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 - +@click.command('logmon') +@click.option('--port', 'port', type=int, + default=logging.handlers.DEFAULT_TCP_LOGGING_PORT, + show_default=True, + help='port where log server is running') +@click.option('--log-name', 'log_name', default=None, + help='filter specific log object') +@click.option('--log-level', 'log_level', + type=click.Choice(['critical', 'error', 'warning', 'info', + 'debug', 'trace']), + default='debug', show_default=True, + help='filter specific log level') +def logmon_cmd(port, log_name, log_level): + """Show the console-based Taurus Remote Log Monitor""" + import taurus host = socket.gethostname() + level = getattr(taurus, log_level.capitalize(), taurus.Trace) - 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=host, port=port, name=log_name, level=level) - log(host, port, name=name, level=level) if __name__ == '__main__': - main() + logmon_cmd() diff --git a/lib/taurus/core/util/tablepprint.py b/lib/taurus/core/util/tablepprint.py index cab4c13e..70552cfe 100644 --- a/lib/taurus/core/util/tablepprint.py +++ b/lib/taurus/core/util/tablepprint.py @@ -41,23 +41,21 @@ __docformat__ = "restructuredtext" def indent(rows, hasHeader=False, headerChar='-', delim=' | ', justify='left', separateRows=False, prefix='', postfix='', wrapfunc=lambda x: x): """Indents a table by column. - - rows: A sequence of sequences of items, one sequence per row. - - hasHeader: True if the first row consists of the columns' names. - - headerChar: Character to be used for the row separator line - (if hasHeader==True or separateRows==True). - - delim: The column delimiter. - - justify: Determines how are data justified in their column. - Valid values are 'left','right' and 'center'. - - separateRows: True if rows are to be separated by a line - of 'headerChar's. - - prefix: A string prepended to each printed row. - - postfix: A string appended to each printed row. - - wrapfunc: A function f(text) for wrapping text; each element in - the table is first wrapped by this function. - - Returns a list of strings. One for each row of the table + :param rows: A sequence of sequences of items, one sequence per row. + :param hasHeader: True if the first row consists of the columns' names. + :param headerChar: Character to be used for the row separator line + (if hasHeader==True or separateRows==True). + :param delim: The column delimiter. + :param justify: Determines how are data justified in their column. + Valid values are 'left','right' and 'center'. + :param separateRows: True if rows are to be separated by a line of + 'headerChar's. + :param prefix: A string prepended to each printed row. + :param postfix: A string appended to each printed row. + :param wrapfunc: A function f(text) for wrapping text; + each element in the table is first wrapped by this function. + :return: a list of strings. One for each row of the table """ - # closure for breaking logical rows to physical, using wrapfunc def rowWrapper(row): newRows = [wrapfunc(item).split('\n') for item in row] @@ -102,10 +100,9 @@ def indent(rows, hasHeader=False, headerChar='-', delim=' | ', justify='left', def wrap_onspace(text, width): - """ - A word-wrap function that preserves existing line breaks + """A word-wrap function that preserves existing line breaks and most spaces in the text. Expects that existing line - breaks are posix newlines (\n). + breaks are posix newlines (\\\\n). """ return reduce(lambda line, word, width=width: '%s%s%s' % (line, diff --git a/lib/taurus/core/util/test/test_codecs.py b/lib/taurus/core/util/test/test_codecs.py index 0543ca87..0746a5d8 100644 --- a/lib/taurus/core/util/test/test_codecs.py +++ b/lib/taurus/core/util/test/test_codecs.py @@ -38,7 +38,7 @@ import numpy @insertTest(helper_name='encDec', cname='json', data=[1, 2, 3]) @insertTest(helper_name='encDec', cname='zip', data=b'foobar') -@insertTest(helper_name='encDec', cname='zip_json', data=[1, 2, 3]) +@insertTest(helper_name='encDec', cname='zip_utf8_json', data=[1, 2, 3]) @insertTest(helper_name='encDec', cname='videoimage', data=numpy.ones((2, 2), dtype='uint8')) @insertTest(helper_name='encDec', cname='zip_null_zip_videoimage', diff --git a/lib/taurus/core/util/whichexecutable.py b/lib/taurus/core/util/whichexecutable.py index 29ce10e6..926e0980 100644 --- a/lib/taurus/core/util/whichexecutable.py +++ b/lib/taurus/core/util/whichexecutable.py @@ -42,7 +42,7 @@ def whichfile(filename, exts=None): Example:: # on a debian machine with taurus installed in the default path: - whichfile('taurusform') --> '/usr/bin/taurusform' + whichfile('taurus') --> '/usr/bin/taurus' # or, on a winXP machine: whichfile('command') --> 'C:\\WINDOWS\\system32\\command.COM' |