1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
#****************************************************************************
# unitatom.py, provides class to hold data on each available unit
#
# ConvertAll, a units conversion program
# Copyright (C) 2014, Douglas W. Bell
#
# This is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License, either Version 2 or any later
# version. This program is distributed in the hope that it will be useful,
# but WITTHOUT ANY WARRANTY. See the included LICENSE file for details.
#*****************************************************************************
import re
import copy
import unitdata
class UnitAtom(object):
"""Reads and stores a single unit conversion.
"""
partialExp = 1000
badOpRegEx = re.compile(r'[^\d\.eE\+\-\*/]')
eqnRegEx = re.compile(r'\[(.*?)\](.*)')
def __init__(self, dataStr):
dataList = dataStr.split('#')
unitList = dataList.pop(0).split('=', 1)
self.name = unitList.pop(0).strip()
self.equiv = ''
self.factor = 1.0
self.fromEqn = '' # used only for non-linear units
self.toEqn = '' # used only for non-linear units
if unitList:
self.equiv = unitList[0].strip()
if self.equiv[0] == '[': # used only for non-linear units
try:
self.equiv, self.fromEqn = UnitAtom.eqnRegEx.\
match(self.equiv).groups()
if ';' in self.fromEqn:
self.fromEqn, self.toEqn = self.fromEqn.split(';', 1)
self.toEqn = self.toEqn.strip()
self.fromEqn = self.fromEqn.strip()
except AttributeError:
raise unitdata.UnitDataError(_('Bad equation for "{0}"').
format(self.name))
else: # split factor and equiv unit for linear
parts = self.equiv.split(None, 1)
if len(parts) > 1 and \
UnitAtom.badOpRegEx.search(parts[0]) == None:
# only allowed digits and operators
try:
self.factor = float(eval(parts[0]))
self.equiv = parts[1]
except:
pass
self.comments = [comm.strip() for comm in dataList]
self.comments.extend([''] * (2 - len(self.comments)))
self.exp = 1
self.viewLink = [None, None]
self.typeName = ''
def description(self):
"""Return name and 1st comment (usu. full name) if applicable.
"""
if self.comments[0]:
return '{0} ({1})'.format(self.name, self.comments[0])
return self.name
def unitValid(self):
"""Return True if unit and exponent are valid.
"""
if self.equiv and \
-UnitAtom.partialExp < self.exp < UnitAtom.partialExp:
return True
return False
def unitText(self, absExp=False):
"""Return text for unit name with exponent or absolute value of exp.
"""
exp = self.exp
if absExp:
exp = abs(self.exp)
if exp == 1:
return self.name
if -UnitAtom.partialExp < exp < UnitAtom.partialExp:
return '{0}^{1}'.format(self.name, exp)
if exp > 1:
return '{0}^'.format(self.name)
else:
return '{0}^-'.format(self.name)
def matchWords(self, wordList):
"""Return True if unit name and comments match word list.
"""
dataStr = ' '.join((self.name, self.comments[0],
self.comments[1])).lower()
for word in wordList:
if dataStr.find(word) == -1:
return False
return True
def copy(self):
"""Return a copy of the unit so the exponent can be changed.
"""
return copy.copy(self)
def __lt__(self, other):
"""Less than comparison for sorting.
"""
return self.name.lower() < other.name.lower()
def __eq__(self, other):
"""Equality test.
"""
return self.name.lower() == other.name.lower()
|