Project

General

Profile

1
# Quantities with units
2
# This file's encoding must be UTF-8Y with BOM so Python will auto-detect UTF-8
3

    
4
import re
5

    
6
import format
7
import strings
8
import util
9

    
10
class MissingUnitsException(Exception):
11
    def __init__(self, quantity):
12
        Exception.__init__(self, 'Quantity has no units: '
13
            +strings.ustr(quantity))
14

    
15
def std_units(units):
16
    if units == None: return units
17
    else: return strings.remove_suffix('.', units) # for abbr ending in '.'
18
    # TODO: deal with '"° and abbrs
19

    
20
class Quantity:
21
    def __init__(self, value='', units=None):
22
        self.value = value
23
        self.units = std_units(util.none_if(units, u''))
24

    
25
def quantity2str(quantity):
26
    str_ = quantity.value
27
    if quantity.units != None: str_ += ' '+quantity.units
28
    return str_
29

    
30
Quantity.__str__ = quantity2str
31
Quantity.__repr__ = quantity2str
32

    
33
def str2quantity(str_):
34
    value = str_
35
    units = None
36
    if not str_.isdigit(): # optimization to avoid regexp for simple cases
37
        match = re.match(ur'(?i)^\s*(.*?\d\.?)\s*([a-z%\'"°][\w.*/^-]*?)?\s*$',
38
            str_)
39
        if match: value, units = match.groups() # has units
40
    return Quantity(value, units)
41

    
42
def set_default_units(quantity, units):
43
    if quantity.units == None: quantity.units = units
44

    
45
conversions = {
46
    ('%', None): 1./100
47
}
48

    
49
def convert(quantity, units):
50
    units = std_units(units)
51
    if quantity.units == units: return quantity # units already correct
52
    try: conversion = conversions[(quantity.units, units)]
53
    except KeyError:
54
        if units == None: return Quantity(quantity.value, units) # remove units
55
        elif quantity.units == None: raise MissingUnitsException(quantity)
56
            # can't convert quantity with unknown units
57
        else: raise NotImplementedError('Unit conversion not implemented yet')
58
    else:
59
        return Quantity(str(format.str2float(quantity.value)*conversion), units)
(39-39/45)