From df81742100f36d26d12925f69eedf42086e0fba5 Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Tue, 6 Jun 2017 14:15:40 +0100 Subject: [PATCH] instrument: add conversion support to MeasurementType - Change MeasurementType to derive from object rather than tuple. - There is now support for conversion from one MeasurementType to another. A MeasurementType defines what it can be converted to and how. --- devlib/instrument/__init__.py | 53 ++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/devlib/instrument/__init__.py b/devlib/instrument/__init__.py index 9d898c4..e599e20 100644 --- a/devlib/instrument/__init__.py +++ b/devlib/instrument/__init__.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import division import csv import logging import collections @@ -24,28 +25,33 @@ from devlib.utils.types import numeric INSTANTANEOUS = 1 CONTINUOUS = 2 +MEASUREMENT_TYPES = {} # populated further down -class MeasurementType(tuple): - __slots__ = [] +class MeasurementType(object): - def __new__(cls, name, units, category=None): - return tuple.__new__(cls, (name, units, category)) + def __init__(self, name, units, category=None, conversions=None): + self.name = name + self.units = units + self.category = category + self.conversions = {} + if conversions is not None: + for key, value in conversions.iteritems(): + if not callable(value): + msg = 'Converter must be callable; got {} "{}"' + raise ValueError(msg.format(type(value), value)) + self.conversions[key] = value - @property - def name(self): - return tuple.__getitem__(self, 0) - - @property - def units(self): - return tuple.__getitem__(self, 1) - - @property - def category(self): - return tuple.__getitem__(self, 2) - - def __getitem__(self, item): - raise TypeError() + def convert(self, value, to): + if isinstance(to, basestring) and to in MEASUREMENT_TYPES: + to = MEASUREMENT_TYPES[to] + if not isinstance(to, MeasurementType): + msg = 'Unexpected conversion target: "{}"' + raise ValueError(msg.format(to)) + if not to.name in self.conversions: + msg = 'No conversion from {} to {} available' + raise ValueError(msg.format(self.name, to.name)) + return self.conversions[to.name](value) def __cmp__(self, other): if isinstance(other, MeasurementType): @@ -55,7 +61,13 @@ class MeasurementType(tuple): def __str__(self): return self.name - __repr__ = __str__ + def __repr__(self): + if self.category: + text = 'MeasurementType({}, {}, {})' + return text.format(self.name, self.units, self.category) + else: + text = 'MeasurementType({}, {})' + return text.format(self.name, self.units) # Standard measures @@ -72,7 +84,8 @@ _measurement_types = [ MeasurementType('rx', 'bytes', 'data transfer'), MeasurementType('tx/rx', 'bytes', 'data transfer'), ] -MEASUREMENT_TYPES = {m.name: m for m in _measurement_types} +for m in _measurement_types: + MEASUREMENT_TYPES[m.name] = m class Measurement(object):