import pint class ConverterError(Exception): pass class Converter(object): def __init__(self): self.ureg = pint.UnitRegistry(autoconvert_offset_to_baseunit=True) self.ureg.define('degreeC = kelvin; offset: 273.15 = °C = C') self.ureg.define('degreeF = 5 / 9 * kelvin; offset: 255.372222 = °F = F') self.default_units = { self.ureg.degC: self.ureg.degreeF, self.ureg.degreeC: self.ureg.degreeF, self.ureg.degF: self.ureg.degreeC, self.ureg.degreeF: self.ureg.degreeC, self.ureg.kilometer: self.ureg.mile, self.ureg.meter: self.ureg.foot, self.ureg.centimeter: self.ureg.inch, self.ureg.millimeter: self.ureg.inch, self.ureg.mile: self.ureg.kilometer, self.ureg.foot: self.ureg.meter, self.ureg.inch: self.ureg.millimeter, self.ureg.kilogram: self.ureg.pound, self.ureg.pound: self.ureg.kilogram, self.ureg.ounce: self.ureg.kilogram, self.ureg.liter: self.ureg.gallon, self.ureg.milliliter: self.ureg.floz, self.ureg.gallon: self.ureg.liter, self.ureg.floz: self.ureg.milliliter, } def update_currencies(self, base, rates): self.ureg.define('{0} = [currency]'.format(base)) for currency, rate in rates.items(): self.ureg.define('{0} = {1} / {2}'.format(currency, base, rate)) def convert(self, expression, unit=None): try: q = self.ureg.parse_expression(expression) except pint.errors.UndefinedUnitError: raise ConverterError('unknown units') try: q.units except AttributeError: if unit is not None: q = self.ureg.parse_expression(expression + unit) unit = None else: raise ConverterError('unknown units') try: q.units except AttributeError: raise ConverterError('unknown units') if unit is not None: try: u = self.ureg.parse_units(unit) except pint.errors.UndefinedUnitError: raise ConverterError('unknown units') else: try: u = self.default_units[q.units] except KeyError: raise ConverterError('no target units specified') try: result = q.to(u) except pint.errors.DimensionalityError: raise ConverterError('invalid conversion') return '{:0.5g~P}'.format(result)