Coverage for tests/test_measurements.py : 14%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#
2# LSST Data Management System
3#
4# This product includes software developed by the
5# LSST Project (http://www.lsst.org/).
6#
7# See COPYRIGHT file at the top of the source tree.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the LSST License Statement and
20# the GNU General Public License along with this program. If not,
21# see <https://www.lsstcorp.org/LegalNotices/>.
22#
24import unittest
25import yaml
27import astropy.units as u
28from astropy.tests.helper import quantity_allclose
30from lsst.utils.tests import TestCase
31from lsst.verify import Measurement, Metric, Name, Blob, BlobSet, Datum
34class MeasurementTestCase(TestCase):
35 """Test lsst.verify.measurment.Measurement class."""
37 def setUp(self):
38 self.pa1 = Metric(
39 'validate_drp.PA1',
40 "The maximum rms of the unresolved source magnitude distribution "
41 "around the mean value (repeatability).",
42 'mmag',
43 tags=['photometric', 'LPM-17'],
44 reference_doc='LPM-17',
45 reference_url='http://ls.st/lpm-17',
46 reference_page=21)
48 self.blob1 = Blob('Blob1')
49 self.blob1['datum1'] = Datum(5 * u.arcsec, 'Datum 1')
50 self.blob1['datum2'] = Datum(28. * u.mag, 'Datum 2')
52 self.blob2 = Blob('Blob2')
53 self.blob2['datumN'] = Datum(11 * u.dimensionless_unscaled, 'Count')
55 def test_PA1_measurement_with_metric(self):
56 """Standard metric with a given Metric instance."""
57 measurement = Measurement(self.pa1, 0.002 * u.mag, blobs=[self.blob1],
58 notes={'filter_name': 'r'})
59 measurement.link_blob(self.blob2)
61 measurement2 = Measurement(self.pa1, 0.002 * u.mag)
63 self.assertTrue(quantity_allclose(measurement.quantity, 0.002 * u.mag))
64 self.assertIsInstance(measurement.metric_name, Name)
65 self.assertEqual(measurement.metric_name, Name('validate_drp.PA1'))
66 self.assertEqual(measurement.metric, self.pa1)
67 self.assertNotEqual(measurement.identifier, measurement2.identifier)
69 # Test blob access
70 self.assertIn('Blob1', measurement.blobs)
71 self.assertIn('Blob2', measurement.blobs)
73 # Test Datum representation
74 datum = measurement.datum
75 self.assertTrue(quantity_allclose(datum.quantity, 0.002 * u.mag))
76 self.assertEqual(datum.label, str(self.pa1.name))
77 self.assertEqual(datum.description, str(self.pa1.description))
79 # Test notes (MeasurementNotes)
80 self.assertEqual(measurement.notes['filter_name'], 'r')
81 # Add a note
82 measurement.notes['camera'] = 'MegaCam'
83 self.assertEqual(measurement.notes['camera'], 'MegaCam')
84 self.assertEqual(len(measurement.notes), 2)
85 self.assertIn('camera', measurement.notes)
86 self.assertIn('filter_name', measurement.notes)
87 # Prefixed keys
88 self.assertIn('validate_drp.PA1.camera', measurement.notes)
89 # test iteration
90 iterkeys = set([key for key in measurement.notes])
91 self.assertEqual(len(iterkeys), 2)
92 self.assertEqual(set(iterkeys), set(measurement.notes.keys()))
93 itemkeys = set()
94 for key, value in measurement.notes.items():
95 self.assertEqual(measurement.notes[key], value)
96 itemkeys.add(key)
97 self.assertEqual(itemkeys, iterkeys)
98 # Test update
99 measurement.notes.update({'photometric': True, 'facility': 'CFHT'})
100 self.assertIn('photometric', measurement.notes)
101 # Test delete
102 del measurement.notes['photometric']
103 self.assertNotIn('photometric', measurement.notes)
105 # Test serialization
106 json_doc = measurement.json
107 # Units should be cast to those of the metric
108 self.assertEqual(json_doc['unit'], 'mmag')
109 self.assertFloatsAlmostEqual(json_doc['value'], 2.0)
110 self.assertEqual(json_doc['identifier'], measurement.identifier)
111 self.assertIsInstance(json_doc['blob_refs'], list)
112 self.assertIn(self.blob1.identifier, json_doc['blob_refs'])
113 self.assertIn(self.blob2.identifier, json_doc['blob_refs'])
114 # No extras, so should not be serialized
115 self.assertNotIn(measurement.extras.identifier, json_doc['blob_refs'])
117 # Test deserialization
118 new_measurement = Measurement.deserialize(
119 blobs=BlobSet([self.blob1, self.blob2]),
120 **json_doc)
121 # shim in original notes; normally these are deserialized via the
122 # Job object.
123 new_measurement.notes.update(measurement.notes)
124 self.assertEqual(measurement, new_measurement)
125 self.assertEqual(measurement.identifier, new_measurement.identifier)
126 self.assertIn('Blob1', measurement.blobs)
127 self.assertIn('Blob2', measurement.blobs)
129 def test_PA1_measurement_without_metric(self):
130 """Test a measurement without a Metric instance."""
131 measurement = Measurement('validate_drp.PA1', 0.002 * u.mag)
133 self.assertIsInstance(measurement.metric_name, Name)
134 self.assertEqual(measurement.metric_name, Name('validate_drp.PA1'))
135 self.assertIsNone(measurement.metric)
137 json_doc = measurement.json
138 # Units are not converted
139 self.assertEqual(json_doc['unit'], 'mag')
140 self.assertFloatsAlmostEqual(json_doc['value'], 0.002)
142 new_measurement = Measurement.deserialize(**json_doc)
143 self.assertEqual(measurement, new_measurement)
144 self.assertEqual(measurement.identifier, new_measurement.identifier)
146 def test_PA1_deferred_metric(self):
147 """Test a measurement when the Metric instance is added later."""
148 measurement = Measurement('PA1', 0.002 * u.mag)
150 self.assertIsNone(measurement.metric)
151 self.assertEqual(measurement.metric_name, Name(metric='PA1'))
153 # Try adding in a metric with the wrong units to existing quantity
154 other_metric = Metric('testing.other', 'Incompatible units', 'arcsec')
155 with self.assertRaises(TypeError):
156 measurement.metric = other_metric
158 # Add metric in; the name should also update
159 measurement.metric = self.pa1
160 self.assertEqual(measurement.metric, self.pa1)
161 self.assertEqual(measurement.metric_name, self.pa1.name)
163 def test_PA1_deferred_quantity(self):
164 """Test a measurement where the quantity is added later."""
165 measurement = Measurement(self.pa1)
166 json_doc = measurement.json
167 self.assertIsNone(json_doc['unit'])
168 self.assertIsNone(json_doc['value'])
170 with self.assertRaises(TypeError):
171 # wrong units
172 measurement.quantity = 5 * u.arcsec
174 measurement.quantity = 5 * u.mmag
175 quantity_allclose(measurement.quantity, 5 * u.mmag)
177 def test_creation_with_extras(self):
178 """Test creating a measurement with an extra."""
179 measurement = Measurement(
180 self.pa1, 5. * u.mmag,
181 extras={'extra1': Datum(10. * u.arcmin, 'Extra 1')})
183 self.assertIn(str(self.pa1.name), measurement.blobs)
184 self.assertIn('extra1', measurement.extras)
186 json_doc = measurement.json
187 self.assertIn(measurement.extras.identifier, json_doc['blob_refs'])
189 blobs = BlobSet([b for k, b in measurement.blobs.items()])
190 new_measurement = Measurement.deserialize(blobs=blobs, **json_doc)
191 self.assertIn('extra1', new_measurement.extras)
192 self.assertEqual(measurement, new_measurement)
193 self.assertEqual(measurement.identifier, new_measurement.identifier)
195 def test_deferred_extras(self):
196 """Test adding extras to an existing measurement."""
197 measurement = Measurement(self.pa1, 5. * u.mmag)
199 self.assertIn(str(self.pa1.name), measurement.blobs)
201 measurement.extras['extra1'] = Datum(10. * u.arcmin, 'Extra 1')
202 self.assertIn('extra1', measurement.extras)
204 def test_quantity_coercion(self):
205 # strings can't be changed into a Quantity
206 with self.assertRaises(TypeError):
207 Measurement('test_metric', quantity='hello')
208 # objects can't be a Quantity
209 with self.assertRaises(TypeError):
210 Measurement('test_metric', quantity=int)
211 m = Measurement('test_metric', quantity=5)
212 self.assertEqual(m.quantity, 5)
213 m = Measurement('test_metric', quantity=5.1)
214 self.assertEqual(m.quantity, 5.1)
216 def test_str(self):
217 metric = 'test.cmodel_mag'
218 value = 1235 * u.mag
219 m = Measurement(metric, value)
220 self.assertEqual(str(m), "test.cmodel_mag: 1235.0 mag")
222 def _check_yaml_round_trip(self, old_measurement):
223 persisted = yaml.dump(old_measurement)
224 new_measurement = yaml.safe_load(persisted)
226 self.assertEqual(old_measurement, new_measurement)
227 # These fields don't participate in Measurement equality
228 self.assertEqual(old_measurement.identifier,
229 new_measurement.identifier)
230 self.assertEqual(old_measurement.blobs,
231 new_measurement.blobs)
232 self.assertEqual(old_measurement.extras,
233 new_measurement.extras)
235 def test_yamlpersist_basic(self):
236 measurement = Measurement('validate_drp.PA1', 0.002 * u.mag)
237 self._check_yaml_round_trip(measurement)
239 def test_yamlpersist_complex(self):
240 measurement = Measurement(
241 self.pa1,
242 5. * u.mmag,
243 notes={'filter_name': 'r'},
244 blobs=[self.blob1],
245 extras={'extra1': Datum(10. * u.arcmin, 'Extra 1')}
246 )
247 self._check_yaml_round_trip(measurement)
250if __name__ == "__main__": 250 ↛ 251line 250 didn't jump to line 251, because the condition on line 250 was never true
251 unittest.main()