Skip to content

Commit

Permalink
Add exitStatus to output with tests
Browse files Browse the repository at this point in the history
Added doRaise exitStatus handling in TaskRunner
  • Loading branch information
parejkoj committed Oct 26, 2017
1 parent c7bdbdc commit 13896a5
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 9 deletions.
40 changes: 31 additions & 9 deletions python/lsst/jointcal/jointcal.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,34 @@ def __call__(self, args):
@param args Arguments for Task.run()
@return
- None if self.doReturnResults is False
- A pipe.base.Struct containing these fields if self.doReturnResults is False:
- ``exitStatus`: 0 if the task completed successfully, 1 otherwise.
- A pipe.base.Struct containing these fields if self.doReturnResults is True:
- dataRef: the provided data references, with update post-fit WCS's.
- ``result``: the result of calling jointcal.run()
- ``exitStatus`: 0 if the task completed successfully, 1 otherwise.
"""
exitStatus = 0 # exit status for shell

# NOTE: cannot call self.makeTask because that assumes args[0] is a single dataRef.
dataRefList, kwargs = args
butler = kwargs.pop('butler')
task = self.TaskClass(config=self.config, log=self.log, butler=butler)
result = task.run(dataRefList, **kwargs)
result = None
try:
result = task.run(dataRefList, **kwargs)
exitStatus = result.exitStatus
except Exception as e: # catch everything, sort it out later.
if self.doRaise:
raise e
else:
exitStatus = 1
eName = type(e).__name__
task.log.fatal("Failed on dataIds=%s: %s: %s", dataRefList, eName, e)

if self.doReturnResults:
return pipeBase.Struct(result=result)
return pipeBase.Struct(result=result, exitStatus=exitStatus)
else:
return pipeBase.Struct(exitStatus=exitStatus)


class JointcalConfig(pexConfig.Config):
Expand Down Expand Up @@ -251,9 +268,9 @@ def _build_ccdImage(self, dataRef, associations, jointcalControl):
goodSrc = self.sourceSelector.selectSources(src)

if len(goodSrc.sourceCat) == 0:
self.log.warn("no stars selected in ", visit, ccdname)
return tanWcs
self.log.info("%d stars selected in visit %d ccd %d", len(goodSrc.sourceCat), visit, ccdname)
self.log.warn("No stars selected in visit %s ccd %s", visit, ccdname)
else:
self.log.info("%d stars selected in visit %d ccd %d", len(goodSrc.sourceCat), visit, ccdname)
associations.addImage(goodSrc.sourceCat, tanWcs, visitInfo, bbox, filterName, photoCalib, detector,
visit, ccdname, jointcalControl)

Expand Down Expand Up @@ -282,7 +299,9 @@ def run(self, dataRefs, profile_jointcal=False):
* metrics: dictionary of internally-computed metrics for testing/validation.
"""
if len(dataRefs) == 0:
raise ValueError('Need a list of data references!')
raise ValueError('Need a non-empty list of data references!')

exitStatus = 0 # exit status for shell

sourceFluxField = "slot_%sFlux" % (self.sourceSelector.config.sourceFluxType,)
jointcalControl = lsst.jointcal.JointcalControl(sourceFluxField)
Expand Down Expand Up @@ -354,7 +373,10 @@ def run(self, dataRefs, profile_jointcal=False):
with pipeBase.cmdLineTask.profile(load_cat_prof_file):
self._write_results(associations, astrometry.model, photometry.model, visit_ccd_to_dataRef)

return pipeBase.Struct(dataRefs=dataRefs, oldWcsList=oldWcsList, metrics=self.metrics)
return pipeBase.Struct(dataRefs=dataRefs,
oldWcsList=oldWcsList,
metrics=self.metrics,
exitStatus=exitStatus)

def _do_load_refcat_and_fit(self, associations, defaultFilter, center, radius,
name="", refObjLoader=None, filters=[], fit_function=None,
Expand Down
1 change: 1 addition & 0 deletions tests/jointcalTestBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def _runJointcalTask(self, nCatalogs, caller, metrics=None):
args.extend(self.other_args)
result = jointcal.JointcalTask.parseAndRun(args=args, doReturnResults=True, config=self.config)
self.assertNotEqual(result.resultList, [], 'resultList should not be empty')
self.assertEqual(result.resultList[0].exitStatus, 0)

self._test_metrics(result.resultList[0].result.metrics, metrics)

Expand Down
64 changes: 64 additions & 0 deletions tests/test_jointcal_cfht_minimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from lsst.meas.extensions.astrometryNet import LoadAstrometryNetObjectsTask

import jointcalTestBase
from lsst.jointcal import jointcal


# for MemoryTestCase
Expand Down Expand Up @@ -66,6 +67,69 @@ def test_jointcalTask_2_visits_photometry(self):
caller = inspect.stack()[1][3] # NOTE: could be inspect.stack()[1].function in py3.5
self._runJointcalTask(2, caller, metrics=metrics)

def test_jointcalTask_fails_raise(self):
"""Raise an exception if there is no data to process."""
self.config = lsst.jointcal.jointcal.JointcalConfig()
self.config.setDefaults()
self.config.photometryRefObjLoader.retarget(LoadAstrometryNetObjectsTask)
self.config.sourceSelector['astrometry'].minSnr = 10000
self.config.doAstrometry = False

# the calling method is one step back on the stack: use it to specify the output repo.
caller = inspect.stack()[1][3] # NOTE: could be inspect.stack()[1].function in py3.5
nCatalogs = 2
visits = '^'.join(str(v) for v in self.all_visits[:nCatalogs])
output_dir = os.path.join('.test', self.__class__.__name__, caller)
args = [self.input_dir, '--output', output_dir,
'--clobber-versions', '--clobber-config',
'--doraise',
'--id', 'visit=%s'%visits]
args.extend(self.other_args)
with self.assertRaises(RuntimeError):
jointcal.JointcalTask.parseAndRun(args=args, doReturnResults=True, config=self.config)

def test_jointcalTask_fails_no_raise(self):
"""exitStatus=1 if there is no data to process."""
self.config = lsst.jointcal.jointcal.JointcalConfig()
self.config.setDefaults()
self.config.photometryRefObjLoader.retarget(LoadAstrometryNetObjectsTask)
self.config.sourceSelector['astrometry'].minSnr = 10000
self.config.doAstrometry = False

# the calling method is one step back on the stack: use it to specify the output repo.
caller = inspect.stack()[1][3] # NOTE: could be inspect.stack()[1].function in py3.5
nCatalogs = 2
visits = '^'.join(str(v) for v in self.all_visits[:nCatalogs])
output_dir = os.path.join('.test', self.__class__.__name__, caller)
args = [self.input_dir, '--output', output_dir,
'--clobber-versions', '--clobber-config',
'--noExit', # have to specify noExit, otherwise the test quits
'--id', 'visit=%s'%visits]
args.extend(self.other_args)
result = jointcal.JointcalTask.parseAndRun(args=args, doReturnResults=True, config=self.config)
self.assertEqual(result.resultList[0].exitStatus, 1)

def test_jointcalTask_fails_no_raise_no_return_results(self):
"""exitStatus=1 if there is no data to process."""
self.config = lsst.jointcal.jointcal.JointcalConfig()
self.config.setDefaults()
self.config.photometryRefObjLoader.retarget(LoadAstrometryNetObjectsTask)
self.config.sourceSelector['astrometry'].minSnr = 10000
self.config.doAstrometry = False

# the calling method is one step back on the stack: use it to specify the output repo.
caller = inspect.stack()[1][3] # NOTE: could be inspect.stack()[1].function in py3.5
nCatalogs = 2
visits = '^'.join(str(v) for v in self.all_visits[:nCatalogs])
output_dir = os.path.join('.test', self.__class__.__name__, caller)
args = [self.input_dir, '--output', output_dir,
'--clobber-versions', '--clobber-config',
'--noExit', # have to specify noExit, otherwise the test quits
'--id', 'visit=%s'%visits]
args.extend(self.other_args)
result = jointcal.JointcalTask.parseAndRun(args=args, config=self.config)
self.assertEqual(result.resultList[0].exitStatus, 1)


class MemoryTester(lsst.utils.tests.MemoryTestCase):
pass
Expand Down

0 comments on commit 13896a5

Please sign in to comment.