"""
A unit converter that can both represent units and convert between units of
different types.
"""
from abc import ABC
from dataclasses import dataclass
__all__= ["UnitConverter","ConverterLength", "ConverterLengthImperialinch",
"ConverterForce","ConverterStress","ConverterDensity"]
@dataclass
class Unit:
name:str
factor:float
[docs]class UnitConverter(ABC):
"""
The base unit converter class, contains interfaces all unit converter
classes use.
"""
unitDict = {}
def _unsupportedException(self, unit):
raise Exception(f'Unit {unit} is unspported, expected one of '\
f'{list(self.unitDict.keys())}')
def _checkInDict(self, unit) -> bool:
if unit in self.unitDict:
return True
else:
self._unsupportedException(unit)
[docs] def convert(self, inputUnit:str, outputUnit:str, value:float):
"""
Converts the value of one unit to another unit.
Parameters
----------
inputUnit : str
A string representing the input unit. Must be one of the units in
the the unit converter 'unitDict' attribute.
outputUnit : str
A string representing the output unit. Must be one of the units in
the the unit converter 'unitDict' attribute.
value : float
The current value to be converted.
Returns
-------
float
The "value" converted from the input unit to the output unit.
"""
return value * (self.getConversionFactor(inputUnit, outputUnit))
[docs] def getConversionFactor(self, inputUnit:str, outputUnit:str) -> float:
"""
Finds the conversion factor between two units.
Parameters
----------
inputUnit : str
A string representing the input unit. Must be one of the units in
the the unit converter 'unitDict' attribute.
outputUnit : str
A string representing the output unit. Must be one of the units in
the the unit converter 'unitDict' attribute.
Returns
-------
cfactor: float
The conversion factor between units.
"""
#!!! Consider returning 1 if the units are the same. Check the performance of this.
# Most of the time we expect units to work, so we use try and except.
try:
return self.unitDict[inputUnit] / self.unitDict[outputUnit]
# In the rare case they do not work, find out what went wrong.
except:
self._checkInDict(inputUnit)
self._checkInDict(outputUnit)
raise Exception('Unit conversion error occured, check units.')
[docs] def getFactorUnit(self, unit:str):
"""
Returns the conversion factor for a given unit.
Parameters
----------
outputUnit : str
The input unit type, must be unit from the unit dictionary.
Returns
-------
float
The output conversion factor.
"""
self._checkInDict(unit)
return self.unitDict[unit]
[docs]class ConverterLength(UnitConverter):
"""
A converter for length units. Supports: 'm', 'mm', 'in', 'ft'
"""
type = 'length'
unitDict = {'m':1, 'mm':0.001, 'in':0.0254, 'ft':0.0254*12}
class ConverterLengthImperialinch(UnitConverter):
type = 'length'
unitDict = {'m':39.37, 'mm':0.03937, 'in':1, 'ft':12}
[docs]class ConverterForce(UnitConverter):
"""
A converter for length units. Supports: 'N', 'kN', 'lbf'.
"""
type = 'force'
unitDict = {'N':1, 'kN':1000, 'lbf':4.44822162}
[docs]class ConverterStress(UnitConverter):
type = 'stress'
unitDict = {'Pa':1, 'kPa':1000, 'MPa':1e6, 'GPa':1e9,
'psi':6894.7572932, 'ksi':6894757.2932,
'psf':47.880258888889}
[docs]class ConverterDensity(UnitConverter):
type = 'mass'
unitDict = {'kg/m3':1, 'lbm/ft3':0.062427960576145, 'N/m3':9.8066500286389,
'kN/m3':9.8066500286389 / 1000}