1import pytest 2 3from pint import DimensionalityError 4from pint.testsuite import QuantityTestCase, helpers 5 6 7@helpers.requires_not_uncertainties() 8class TestNotMeasurement(QuantityTestCase): 9 def test_instantiate(self): 10 M_ = self.ureg.Measurement 11 with pytest.raises(RuntimeError): 12 M_(4.0, 0.1, "s") 13 14 15@helpers.requires_uncertainties() 16class TestMeasurement(QuantityTestCase): 17 def test_simple(self): 18 M_ = self.ureg.Measurement 19 M_(4.0, 0.1, "s") 20 21 def test_build(self): 22 M_ = self.ureg.Measurement 23 v, u = self.Q_(4.0, "s"), self.Q_(0.1, "s") 24 M_(v.magnitude, u.magnitude, "s") 25 ms = ( 26 M_(v.magnitude, u.magnitude, "s"), 27 M_(v, u.magnitude), 28 M_(v, u), 29 v.plus_minus(0.1), 30 v.plus_minus(0.025, True), 31 v.plus_minus(u), 32 ) 33 34 for m in ms: 35 assert m.value == v 36 assert m.error == u 37 assert m.rel == m.error / abs(m.value) 38 39 def test_format(self, subtests): 40 v, u = self.Q_(4.0, "s ** 2"), self.Q_(0.1, "s ** 2") 41 m = self.ureg.Measurement(v, u) 42 43 for spec, result in ( 44 ("{}", "(4.00 +/- 0.10) second ** 2"), 45 ("{!r}", "<Measurement(4.0, 0.1, second ** 2)>"), 46 ("{:P}", "(4.00 ± 0.10) second²"), 47 ("{:L}", r"\left(4.00 \pm 0.10\right)\ \mathrm{second}^{2}"), 48 ("{:H}", "(4.00 ± 0.10) second<sup>2</sup>"), 49 ("{:C}", "(4.00+/-0.10) second**2"), 50 ("{:Lx}", r"\SI{4.00 +- 0.10}{\second\squared}"), 51 ("{:.1f}", "(4.0 +/- 0.1) second ** 2"), 52 ("{:.1fP}", "(4.0 ± 0.1) second²"), 53 ("{:.1fL}", r"\left(4.0 \pm 0.1\right)\ \mathrm{second}^{2}"), 54 ("{:.1fH}", "(4.0 ± 0.1) second<sup>2</sup>"), 55 ("{:.1fC}", "(4.0+/-0.1) second**2"), 56 ("{:.1fLx}", r"\SI{4.0 +- 0.1}{\second\squared}"), 57 ): 58 with subtests.test(spec): 59 assert spec.format(m) == result 60 61 def test_format_paru(self, subtests): 62 v, u = self.Q_(0.20, "s ** 2"), self.Q_(0.01, "s ** 2") 63 m = self.ureg.Measurement(v, u) 64 65 for spec, result in ( 66 ("{:uS}", "0.200(10) second ** 2"), 67 ("{:.3uS}", "0.2000(100) second ** 2"), 68 ("{:.3uSP}", "0.2000(100) second²"), 69 ("{:.3uSL}", r"0.2000\left(100\right)\ \mathrm{second}^{2}"), 70 ("{:.3uSH}", "0.2000(100) second<sup>2</sup>"), 71 ("{:.3uSC}", "0.2000(100) second**2"), 72 ): 73 with subtests.test(spec): 74 assert spec.format(m) == result 75 76 def test_format_u(self, subtests): 77 v, u = self.Q_(0.20, "s ** 2"), self.Q_(0.01, "s ** 2") 78 m = self.ureg.Measurement(v, u) 79 80 for spec, result in ( 81 ("{:.3u}", "(0.2000 +/- 0.0100) second ** 2"), 82 ("{:.3uP}", "(0.2000 ± 0.0100) second²"), 83 ("{:.3uL}", r"\left(0.2000 \pm 0.0100\right)\ \mathrm{second}^{2}"), 84 ("{:.3uH}", "(0.2000 ± 0.0100) second<sup>2</sup>"), 85 ("{:.3uC}", "(0.2000+/-0.0100) second**2"), 86 ( 87 "{:.3uLx}", 88 r"\SI{0.2000 +- 0.0100}{\second\squared}", 89 ), 90 ("{:.1uLx}", r"\SI{0.20 +- 0.01}{\second\squared}"), 91 ): 92 with subtests.test(spec): 93 assert spec.format(m) == result 94 95 def test_format_percu(self, subtests): 96 self.test_format_perce(subtests) 97 v, u = self.Q_(0.20, "s ** 2"), self.Q_(0.01, "s ** 2") 98 m = self.ureg.Measurement(v, u) 99 100 for spec, result in ( 101 ("{:.1u%}", "(20 +/- 1)% second ** 2"), 102 ("{:.1u%P}", "(20 ± 1)% second²"), 103 ("{:.1u%L}", r"\left(20 \pm 1\right) \%\ \mathrm{second}^{2}"), 104 ("{:.1u%H}", "(20 ± 1)% second<sup>2</sup>"), 105 ("{:.1u%C}", "(20+/-1)% second**2"), 106 ): 107 with subtests.test(spec): 108 assert spec.format(m) == result 109 110 def test_format_perce(self, subtests): 111 v, u = self.Q_(0.20, "s ** 2"), self.Q_(0.01, "s ** 2") 112 m = self.ureg.Measurement(v, u) 113 for spec, result in ( 114 ("{:.1ue}", "(2.0 +/- 0.1)e-01 second ** 2"), 115 ("{:.1ueP}", "(2.0 ± 0.1)×10⁻¹ second²"), 116 ( 117 "{:.1ueL}", 118 r"\left(2.0 \pm 0.1\right) \times 10^{-1}\ \mathrm{second}^{2}", 119 ), 120 ("{:.1ueH}", "(2.0 ± 0.1)×10<sup>-1</sup> second<sup>2</sup>"), 121 ("{:.1ueC}", "(2.0+/-0.1)e-01 second**2"), 122 ): 123 with subtests.test(spec): 124 assert spec.format(m) == result 125 126 def test_format_exponential_pos(self, subtests): 127 # Quantities in exponential format come with their own parenthesis, don't wrap 128 # them twice 129 m = self.ureg.Quantity(4e20, "s^2").plus_minus(1e19) 130 for spec, result in ( 131 ("{}", "(4.00 +/- 0.10)e+20 second ** 2"), 132 ("{!r}", "<Measurement(4e+20, 1e+19, second ** 2)>"), 133 ("{:P}", "(4.00 ± 0.10)×10²⁰ second²"), 134 ("{:L}", r"\left(4.00 \pm 0.10\right) \times 10^{20}\ \mathrm{second}^{2}"), 135 ("{:H}", "(4.00 ± 0.10)×10<sup>20</sup> second<sup>2</sup>"), 136 ("{:C}", "(4.00+/-0.10)e+20 second**2"), 137 ("{:Lx}", r"\SI{4.00 +- 0.10 e+20}{\second\squared}"), 138 ): 139 with subtests.test(spec): 140 assert spec.format(m) == result 141 142 def test_format_exponential_neg(self, subtests): 143 m = self.ureg.Quantity(4e-20, "s^2").plus_minus(1e-21) 144 for spec, result in ( 145 ("{}", "(4.00 +/- 0.10)e-20 second ** 2"), 146 ("{!r}", "<Measurement(4e-20, 1e-21, second ** 2)>"), 147 ("{:P}", "(4.00 ± 0.10)×10⁻²⁰ second²"), 148 ( 149 "{:L}", 150 r"\left(4.00 \pm 0.10\right) \times 10^{-20}\ \mathrm{second}^{2}", 151 ), 152 ("{:H}", "(4.00 ± 0.10)×10<sup>-20</sup> second<sup>2</sup>"), 153 ("{:C}", "(4.00+/-0.10)e-20 second**2"), 154 ("{:Lx}", r"\SI{4.00 +- 0.10 e-20}{\second\squared}"), 155 ): 156 with subtests.test(spec): 157 assert spec.format(m) == result 158 159 def test_raise_build(self): 160 v, u = self.Q_(1.0, "s"), self.Q_(0.1, "s") 161 o = self.Q_(0.1, "m") 162 163 M_ = self.ureg.Measurement 164 with pytest.raises(DimensionalityError): 165 M_(v, o) 166 with pytest.raises(DimensionalityError): 167 v.plus_minus(o) 168 with pytest.raises(ValueError): 169 v.plus_minus(u, relative=True) 170 171 def test_propagate_linear(self): 172 173 v1, u1 = self.Q_(8.0, "s"), self.Q_(0.7, "s") 174 v2, u2 = self.Q_(5.0, "s"), self.Q_(0.6, "s") 175 v2, u3 = self.Q_(-5.0, "s"), self.Q_(0.6, "s") 176 177 m1 = v1.plus_minus(u1) 178 m2 = v2.plus_minus(u2) 179 m3 = v2.plus_minus(u3) 180 181 for factor, m in zip((3, -3, 3, -3), (m1, m3, m1, m3)): 182 r = factor * m 183 helpers.assert_quantity_almost_equal( 184 r.value.magnitude, factor * m.value.magnitude 185 ) 186 helpers.assert_quantity_almost_equal( 187 r.error.magnitude, abs(factor * m.error.magnitude) 188 ) 189 assert r.value.units == m.value.units 190 191 for ml, mr in zip((m1, m1, m1, m3), (m1, m2, m3, m3)): 192 r = ml + mr 193 helpers.assert_quantity_almost_equal( 194 r.value.magnitude, ml.value.magnitude + mr.value.magnitude 195 ) 196 helpers.assert_quantity_almost_equal( 197 r.error.magnitude, 198 ( 199 ml.error.magnitude + mr.error.magnitude 200 if ml is mr 201 else (ml.error.magnitude ** 2 + mr.error.magnitude ** 2) ** 0.5 202 ), 203 ) 204 assert r.value.units == ml.value.units 205 206 for ml, mr in zip((m1, m1, m1, m3), (m1, m2, m3, m3)): 207 r = ml - mr 208 helpers.assert_quantity_almost_equal( 209 r.value.magnitude, ml.value.magnitude - mr.value.magnitude 210 ) 211 helpers.assert_quantity_almost_equal( 212 r.error.magnitude, 213 0 214 if ml is mr 215 else (ml.error.magnitude ** 2 + mr.error.magnitude ** 2) ** 0.5, 216 ) 217 assert r.value.units == ml.value.units 218 219 def test_propagate_product(self): 220 221 v1, u1 = self.Q_(8.0, "s"), self.Q_(0.7, "s") 222 v2, u2 = self.Q_(5.0, "s"), self.Q_(0.6, "s") 223 v2, u3 = self.Q_(-5.0, "s"), self.Q_(0.6, "s") 224 225 m1 = v1.plus_minus(u1) 226 m2 = v2.plus_minus(u2) 227 m3 = v2.plus_minus(u3) 228 229 m4 = (2.3 * self.ureg.meter).plus_minus(0.1) 230 m5 = (1.4 * self.ureg.meter).plus_minus(0.2) 231 232 for ml, mr in zip((m1, m1, m1, m3, m4), (m1, m2, m3, m3, m5)): 233 r = ml * mr 234 helpers.assert_quantity_almost_equal( 235 r.value.magnitude, ml.value.magnitude * mr.value.magnitude 236 ) 237 assert r.value.units == ml.value.units * mr.value.units 238 239 for ml, mr in zip((m1, m1, m1, m3, m4), (m1, m2, m3, m3, m5)): 240 r = ml / mr 241 helpers.assert_quantity_almost_equal( 242 r.value.magnitude, ml.value.magnitude / mr.value.magnitude 243 ) 244 assert r.value.units == ml.value.units / mr.value.units 245 246 def test_measurement_comparison(self): 247 x = self.Q_(4.2, "meter") 248 y = self.Q_(5.0, "meter").plus_minus(0.1) 249 assert x <= y 250 assert not (x >= y) 251