Skip to content

Commit dd5ebdf

Browse files
committed
added more strict type checking for dimensionality arithmetic operations
beginning improved unit testing, starting with dimensionality
1 parent de9f645 commit dd5ebdf

5 files changed

Lines changed: 101 additions & 23 deletions

File tree

.eric4project/quantities.e4q

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!DOCTYPE UserProject SYSTEM "UserProject-4.0.dtd">
33
<!-- eric4 user project file for project quantities -->
4-
<!-- Saved: 2009-02-10, 17:07:41 -->
4+
<!-- Saved: 2009-02-15, 20:51:10 -->
55
<!-- Copyright (C) 2009 , -->
66
<UserProject version="4.0">
77
</UserProject>

.eric4project/quantities.e4t

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!DOCTYPE Tasks SYSTEM "Tasks-4.2.dtd">
33
<!-- eric4 tasks file for project quantities -->
4-
<!-- Saved: 2009-02-10, 17:07:41 -->
4+
<!-- Saved: 2009-02-15, 20:51:10 -->
55
<Tasks version="4.2">
66
<Task priority="1" completed="False" bugfix="False">
77
<Summary>TODO: move to constants</Summary>
@@ -21,28 +21,19 @@
2121
<Linenumber>101</Linenumber>
2222
</Resource>
2323
</Task>
24-
<Task priority="1" completed="False" bugfix="False">
25-
<Summary>TODO: needs uncertainty: 0.000000083e-27*kg</Summary>
26-
<Description></Description>
27-
<Created>2009-01-14, 17:04:25</Created>
28-
<Resource>
29-
<Filename>quantities/units/mass.py</Filename>
30-
<Linenumber>100</Linenumber>
31-
</Resource>
32-
</Task>
3324
<Task priority="1" completed="False" bugfix="False">
3425
<Summary>TODO: use a regexp:</Summary>
3526
<Description></Description>
36-
<Created>2009-01-23, 06:39:46</Created>
27+
<Created>2009-02-15, 16:07:34</Created>
3728
<Resource>
3829
<Filename>quantities/markup.py</Filename>
39-
<Linenumber>11</Linenumber>
30+
<Linenumber>13</Linenumber>
4031
</Resource>
4132
</Task>
4233
<Task priority="1" completed="False" bugfix="False">
4334
<Summary>TODO: what is an appropriate value?</Summary>
4435
<Description></Description>
45-
<Created>2009-02-08, 10:44:30</Created>
36+
<Created>2009-02-15, 16:27:23</Created>
4637
<Resource>
4738
<Filename>quantities/uncertainquantity.py</Filename>
4839
<Linenumber>15</Linenumber>
@@ -51,19 +42,19 @@
5142
<Task priority="1" completed="False" bugfix="False">
5243
<Summary>TODO: what is an appropriate value?</Summary>
5344
<Description></Description>
54-
<Created>2009-02-08, 13:07:48</Created>
45+
<Created>2009-02-15, 16:27:45</Created>
5546
<Resource>
5647
<Filename>quantities/quantity.py</Filename>
57-
<Linenumber>63</Linenumber>
48+
<Linenumber>64</Linenumber>
5849
</Resource>
5950
</Task>
6051
<Task priority="1" completed="False" bugfix="False">
6152
<Summary>TODO: do we want this kind of magic?</Summary>
6253
<Description></Description>
63-
<Created>2009-02-08, 13:07:49</Created>
54+
<Created>2009-02-15, 16:27:45</Created>
6455
<Resource>
6556
<Filename>quantities/quantity.py</Filename>
66-
<Linenumber>416</Linenumber>
57+
<Linenumber>381</Linenumber>
6758
</Resource>
6859
</Task>
6960
</Tasks>

quantities/dimensionality.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
from .markup import format_units, format_units_unicode
1212
from .registry import unit_registry
1313

14+
def assert_isinstance(obj, types):
15+
assert isinstance(obj, types), "arg %r does not match %s" % (obj, types)
16+
1417

1518
class Dimensionality(dict):
1619

@@ -47,6 +50,7 @@ def __hash__(self):
4750
return res
4851

4952
def __add__(self, other):
53+
assert_isinstance(other, Dimensionality)
5054
try:
5155
assert self == other
5256
except AssertionError:
@@ -57,6 +61,7 @@ def __add__(self, other):
5761
return self.copy()
5862

5963
def __iadd__(self, other):
64+
assert_isinstance(other, Dimensionality)
6065
try:
6166
assert self == other
6267
except AssertionError:
@@ -67,6 +72,7 @@ def __iadd__(self, other):
6772
return self
6873

6974
def __sub__(self, other):
75+
assert_isinstance(other, Dimensionality)
7076
try:
7177
assert self == other
7278
except AssertionError:
@@ -77,6 +83,7 @@ def __sub__(self, other):
7783
return self.copy()
7884

7985
def __isub__(self, other):
86+
assert_isinstance(other, Dimensionality)
8087
try:
8188
assert self == other
8289
except AssertionError:
@@ -87,6 +94,7 @@ def __isub__(self, other):
8794
return self
8895

8996
def __mul__(self, other):
97+
assert_isinstance(other, Dimensionality)
9098
new = Dimensionality(self)
9199
for unit, power in other.iteritems():
92100
try:
@@ -98,6 +106,7 @@ def __mul__(self, other):
98106
return new
99107

100108
def __imul__(self, other):
109+
assert_isinstance(other, Dimensionality)
101110
for unit, power in other.iteritems():
102111
try:
103112
self[unit] += power
@@ -108,6 +117,7 @@ def __imul__(self, other):
108117
return self
109118

110119
def __truediv__(self, other):
120+
assert_isinstance(other, Dimensionality)
111121
new = Dimensionality(self)
112122
for unit, power in other.iteritems():
113123
try:
@@ -119,9 +129,11 @@ def __truediv__(self, other):
119129
return new
120130

121131
def __div__(self, other):
132+
assert_isinstance(other, Dimensionality)
122133
return self.__truediv__(other)
123134

124135
def __itruediv__(self, other):
136+
assert_isinstance(other, Dimensionality)
125137
for unit, power in other.iteritems():
126138
try:
127139
self[unit] -= power
@@ -132,17 +144,20 @@ def __itruediv__(self, other):
132144
return self
133145

134146
def __idiv__(self, other):
147+
assert_isinstance(other, Dimensionality)
135148
return self.__itruediv__(other)
136149

137150
def __pow__(self, other):
138-
assert isinstance(other, (int, float))
151+
assert numpy.isscalar(other), \
152+
'exponent must be a scalar, got %r' % other
139153
new = Dimensionality(self)
140154
for i in new:
141155
new[i] *= other
142156
return new
143157

144158
def __ipow__(self, other):
145-
assert isinstance(other, (int, float))
159+
assert numpy.isscalar(other), \
160+
'exponent must be a scalar, got %r' % other
146161
for i in self:
147162
self[i] *= other
148163
return self

quantities/tests/test_dimensionality.py

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,58 @@ def test_inequality():
4747
assert_true(joule != Joule)
4848
assert_equal(repr(joule), joule_repr)
4949

50+
def test_copy():
51+
temp = meter.copy()
52+
assert_true(temp is not meter)
53+
assert_true(isinstance(temp, Dimensionality))
54+
assert_true(temp == meter)
55+
temp[q.m] += 1
56+
assert_false(temp == meter)
57+
5058
def test_addition():
5159
assert_equal(repr(meter+meter), meter_repr)
5260
assert_true(meter + meter is not meter)
53-
assert_equal(repr(meter), meter_repr)
5461
assert_raises(ValueError, operator.__add__, meter, joule)
5562
assert_raises(ValueError, operator.__add__, Joule, joule)
63+
test_dimensionality_repr()
64+
65+
def test_inplace_addition():
66+
temp = meter.copy()
67+
temp += meter
68+
assert_equal(temp, meter)
69+
assert_raises(ValueError, operator.__iadd__, meter, joule)
70+
assert_raises(ValueError, operator.__iadd__, Joule, joule)
71+
test_dimensionality_repr()
5672

5773
def test_subtraction():
5874
assert_equal(repr(meter-meter), meter_repr)
5975
assert_true(meter - meter is not meter)
60-
assert_equal(repr(meter), meter_repr)
6176
assert_raises(ValueError, operator.__sub__, meter, joule)
6277
assert_raises(ValueError, operator.__sub__, Joule, joule)
63-
78+
test_dimensionality_repr()
79+
80+
def test_inplace_subtraction():
81+
temp = meter.copy()
82+
temp -= meter
83+
assert_equal(temp, meter)
84+
assert_raises(ValueError, operator.__isub__, meter, joule)
85+
assert_raises(ValueError, operator.__isub__, Joule, joule)
86+
test_dimensionality_repr()
87+
88+
def test_multiplication():
89+
assert_equal(meter*meter, Dimensionality([(q.m, 2)]))
90+
assert_equal(joule*meter, Dimensionality([(q.kg, 1), (q.m, 3), (q.s, -2)]))
91+
test_dimensionality_repr()
92+
93+
def test_division():
94+
assert_equal(meter/meter, Dimensionality())
95+
assert_equal(joule/meter, Dimensionality([(q.kg, 1), (q.m, 1), (q.s, -2)]))
96+
test_dimensionality_repr()
97+
98+
def test_power():
99+
assert_equal(meter**2, Dimensionality([(q.m, 2)]))
100+
assert_equal(joule**2, Dimensionality([(q.kg, 2), (q.m, 4), (q.s, -4)]))
101+
test_dimensionality_repr()
64102

65103
def test_simplification():
66104
assert_equal(Joule.simplified.string, 'kg*m**2/s**2')
@@ -72,6 +110,7 @@ def test_gt():
72110
assert_false(meter > Joule)
73111
assert_false(joule > joule)
74112
assert_false(joule > Joule)
113+
test_dimensionality_repr()
75114

76115
def test_ge():
77116
assert_true(joule >= meter)
@@ -80,6 +119,25 @@ def test_ge():
80119
assert_false(meter >= Joule)
81120
assert_true(joule >= joule)
82121
assert_true(joule >= Joule)
122+
test_dimensionality_repr()
123+
124+
def test_lt():
125+
assert_true(meter < joule)
126+
assert_true(meter < Joule)
127+
assert_false(joule < meter)
128+
assert_false(Joule < meter)
129+
assert_false(joule < joule)
130+
assert_false(Joule < joule)
131+
test_dimensionality_repr()
132+
133+
def test_le():
134+
assert_true(meter <= joule)
135+
assert_true(meter <= Joule)
136+
assert_false(joule <= meter)
137+
assert_false(Joule <= meter)
138+
assert_true(joule <= joule)
139+
assert_true(joule <= Joule)
140+
test_dimensionality_repr()
83141

84142

85143

quantities/utilities.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
from functools import wraps
2+
3+
def accepts(*types):
4+
assert len(types), "no types defined"
5+
def check_accepts(f):
6+
@wraps(f)
7+
def new_f(self, other):
8+
assert isinstance(other, types), \
9+
"arg %r does not match %s" % (other, types)
10+
return f(self, other)
11+
return new_f
12+
return check_accepts
13+
14+
115
class with_doc:
216

317
"""

0 commit comments

Comments
 (0)