diff --git a/python/lsst/pipe/tasks/makeCoaddTempExp.py b/python/lsst/pipe/tasks/makeCoaddTempExp.py index 82abecf3a..1faf90ab4 100755 --- a/python/lsst/pipe/tasks/makeCoaddTempExp.py +++ b/python/lsst/pipe/tasks/makeCoaddTempExp.py @@ -363,19 +363,16 @@ def run(self, calexpRefList, skyInfo, visitId=0): for calExpInd, calExpRef in enumerate(calexpRefList): self.log.info("Processing calexp %d of %d for this Warp: id=%s", calExpInd+1, len(calexpRefList), calExpRef.dataId) - try: - ccdId = calExpRef.get("ccdExposureId", immediate=True) - except Exception: - ccdId = calExpInd + ccdId = calExpRef.get("ccdExposureId", immediate=True) try: # We augment the dataRef here with the tract, which is harmless for loading things - # like calexps that don't need the tract, and necessary for meas_mosaic outputs, + # like calexps that don't need the tract, and necessary for jointcal outputs, # which do. calExpRef = calExpRef.butlerSubset.butler.dataRef("calexp", dataId=calExpRef.dataId, tract=skyInfo.tractInfo.getId()) calExp = self.getCalibratedExposure(calExpRef, bgSubtracted=self.config.bgSubtracted) - except Exception as e: - self.log.warn("Calexp %s not found; skipping it: %s", calExpRef.dataId, e) + except MissingExposureError as e: + self.log.warn("Skipping missing data: %s", e) continue if self.config.doApplySkyCorr: diff --git a/tests/test_makeCoaddTempExp.py b/tests/test_makeCoaddTempExp.py index be6a443d6..9a996c01d 100644 --- a/tests/test_makeCoaddTempExp.py +++ b/tests/test_makeCoaddTempExp.py @@ -34,6 +34,7 @@ class GetCalibratedExposureTestCase(lsst.utils.tests.TestCase): + """Tests of MakeCoaddTempExpTask.getCalibratedExposure()""" def setUp(self): np.random.seed(10) @@ -120,6 +121,63 @@ def test_getCalibratedExposureJointcal(self): self.assertEqual(result.getWcs(), self.jointcalSkyWcs) +class MakeCoaddTempExpRunTestCase(lsst.utils.tests.TestCase): + """Tests of MakeCoaddTempExpTask.run().""" + def setUp(self): + self.config = MakeCoaddTempExpConfig() + self.task = MakeCoaddTempExpTask(self.config) + dataId = "visit=mock" + fakeDataRef = unittest.mock.NonCallableMock(lsst.daf.persistence.ButlerDataRef, + dataId=dataId, + butlerSubset=unittest.mock.Mock()) + self.calexpRefList = [fakeDataRef] + + bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(100, 100)) + self.skyInfo = unittest.mock.Mock(bbox=bbox) + + self.fakeImage = lsst.afw.image.ExposureF(bbox) + self.fakeImage.getMaskedImage().set(np.nan, lsst.afw.image.Mask.getPlaneBitMask("NO_DATA"), np.inf) + + target = "lsst.pipe.tasks.makeCoaddTempExp.MakeCoaddTempExpTask._prepareEmptyExposure" + preparePatch = unittest.mock.patch(target, return_value=self.fakeImage) + preparePatch.start() + self.addCleanup(preparePatch.stop) + + def testGetCalibratedExposureRaisesRuntimeError(self): + """If getCalibratedExposure() raises anything other than + MissingExposureError, it should be passed up the chain. + + Previously, all Exceptions were caught, logged at `warn` level, + and then dropped. + """ + mockErr = "Mock Error!" + target = "lsst.pipe.tasks.makeCoaddTempExp.MakeCoaddTempExpTask.getCalibratedExposure" + patch = unittest.mock.patch(target, + new_callable=unittest.mock.Mock, + side_effect=RuntimeError(mockErr)) + patch.start() + self.addCleanup(patch.stop) + with self.assertRaises(RuntimeError) as cm: + self.task.run(self.calexpRefList, self.skyInfo) + self.assertIn(mockErr, str(cm.exception)) + + def testGetCalibratedExposureRaisesMissingExposureError(self): + """If getCalibratedExposure() raises MissingExposureError, + processing should continue uninterrupted. + In this case, that means no data is returned, because there is only + one dataRef available (`self.fakeImage`). + """ + mockErr = "No data files exist." + target = "lsst.pipe.tasks.makeCoaddTempExp.MakeCoaddTempExpTask.getCalibratedExposure" + patch = unittest.mock.patch(target, + new_callable=unittest.mock.Mock, + side_effect=MissingExposureError(mockErr)) + patch.start() + self.addCleanup(patch.stop) + result = self.task.run(self.calexpRefList, self.skyInfo) + self.assertEqual(result.exposures, {"direct": None}) + + def setup_module(module): lsst.utils.tests.init()