Passed
Push — master ( ec8b58...774f6d )
by Velizar
02:44
created

uom.uom   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Test Coverage

Coverage 93.18%

Importance

Changes 0
Metric Value
wmc 43
eloc 92
dl 0
loc 149
ccs 82
cts 88
cp 0.9318
rs 8.96
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
F convert() 0 35 15
F base_unit() 0 50 14
B base_conversion_factors() 0 20 6
B conversion_factors() 0 30 8

How to fix   Complexity   

Complexity

Complex classes like uom.uom often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""UOM conversion tool."""
2 1
from __future__ import absolute_import
3
4 1
from .unit_alias import unit_alias
5 1
from .uomdata import DF_UOM
6
7
8 1
def base_conversion_factors(unit_or_alias, verbose=False):
9
    """Return conversion facors to the base unit."""
10 1
    unit = unit_alias(unit_or_alias)
11
12 1
    if unit not in DF_UOM.index:
13 1
        if verbose:
14 1
            print(f'Unit {unit_or_alias} unknown.')
15
16 1
        return None, None, None
17
18 1
    if verbose:
19 1
        print(unit, DF_UOM['A'][unit], DF_UOM['B'][unit], DF_UOM['C'][unit])
20
21 1
    if DF_UOM['baseUnit'][unit] == 'IS-BASE':
22 1
        if verbose:
23 1
            print('The unit {unit} it is a base unit.')
24
25 1
        return 0, 1, 1
26
27 1
    return DF_UOM['A'][unit], DF_UOM['B'][unit], DF_UOM['C'][unit]
28
29
30 1
def base_unit(unit_or_alias, verbose=False):
31
    """Return base unit."""
32 1
    unit = unit_alias(unit_or_alias)
33
34 1
    if unit not in DF_UOM.index:
35 1
        if verbose:
36 1
            print(f'Unit {unit_or_alias} unknown.')
37
38 1
        return None
39
40 1
    b_unit = DF_UOM['baseUnit'][unit]
41 1
    underlying_def = DF_UOM['underlyingDef'][unit]
42
43 1
    if verbose:
44 1
        print(f'Input: {unit_or_alias}, unit: {unit}, base_unit: {b_unit}, underlying_unit: '
45
              f'{underlying_def}')
46
47 1
    if b_unit == 'IS-BASE':
48 1
        if underlying_def:
49 1
            if underlying_def not in DF_UOM.index:
50 1
                if verbose:
51 1
                    print(f'{unit_or_alias} => {unit} [Case1: IsBase, UD = {underlying_def}, '
52
                          'but not available]>')
53
54 1
                return unit
55
56 1
            if verbose:
57 1
                print(f'{unit_or_alias} => {unit} [Case2: IsBase, UD = {underlying_def} and '
58
                      'available]')
59
60 1
            unit2 = DF_UOM['baseUnit'][underlying_def]
61
62 1
            if unit2 not in DF_UOM.index:
63 1
                if verbose:
64 1
                    print(f'Base unit {unit2} not in the index')
65
66 1
                return underlying_def
67
68
            if verbose:
69
                print(f'Base unit {b_unit} in the index')
70
        else:
71
            if verbose:
72
                print(f'{unit_or_alias} => {unit} [Case3: IsBase, UD is missing]')
73
74
            return unit
75
76 1
    if verbose:
77 1
        print(f'{unit_or_alias} => {b_unit} [Case4: IsNotBase available]')
78
79 1
    return base_unit(b_unit, verbose)
80
81
82 1
def conversion_factors(source, target, verbose=False):
83
    """Return conversion scale and offset."""
84 1
    source_base_unit = base_unit(source, verbose)
85 1
    target_base_unit = base_unit(target, verbose)
86
87 1
    if source_base_unit is None or target_base_unit is None:
88 1
        return None, None
89
90 1
    if source_base_unit != target_base_unit:
91 1
        if verbose:
92 1
            print(f'The units {source} and {target} are not compatible.')
93
94 1
        source_dim = DF_UOM['dimension'][unit_alias(source)]
95
96 1
        if source_dim == DF_UOM['dimension'][unit_alias(target)] and \
97
           source_dim != 'none':
98
            raise Exception('ERROR: Houston, we have a problem')
99
100 1
        return None, None
101
102 1
    source_a, source_b, source_c = base_conversion_factors(source, verbose)
103 1
    target_a, target_b, target_c = base_conversion_factors(target, verbose)
104
105 1
    scale = source_b * target_c / source_c / target_b
106 1
    offset = source_a * target_c / source_c / target_b - target_a / target_b
107
108 1
    if verbose:
109 1
        print(f'Scale: {scale}, offset: {offset}')
110
111 1
    return scale, offset
112
113
114 1
def convert(value, source=None, target=None, verbose=False):
115
    """Convert value(s) from source to target."""
116 1
    if source == target or \
117
            ('unitless' in [source, target] and '' in [source, target]):
118 1
        return value
119
120 1
    if target is None and source is not None:
121 1
        target = base_unit(source, verbose)
122
123 1
        if target is None:
124 1
            return None
125
126 1
    if source is None and target is not None:
127 1
        source = base_unit(target, verbose)
128
129 1
        if source is None:
130 1
            return None
131
132 1
    scale, offset = conversion_factors(source, target, verbose)
133
134 1
    if scale is None or offset is None:
135 1
        return None
136
137 1
    if verbose:
138 1
        print(value, type(value))
139
140 1
    if isinstance(value, list):
141 1
        target_value = [scale * i + offset for i in value]
142
    else:
143 1
        target_value = scale * value + offset
144
145 1
    if verbose:
146 1
        print(target_value, type(target_value))
147
148
    return target_value
149