Skip to content

Commit

Permalink
Generalize MetricsControllerTask's use of SquashMetadataTask.
Browse files Browse the repository at this point in the history
  • Loading branch information
kfindeisen committed Jan 23, 2019
1 parent b7de83c commit 004b440
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 29 deletions.
13 changes: 10 additions & 3 deletions python/lsst/verify/compatibility/metricsControllerTask.py
Expand Up @@ -42,6 +42,14 @@ class MetricsControllerConfig(pexConfig.Config):
"written. {id} is replaced with a unique index (recommended), "
"while {dataId} is replaced with the data ID.",
default="metrics{id}.{dataId}.verify.json")
metadataAdder = pexConfig.ConfigurableField(
target=SquashMetadataTask,
doc="Task for adding metadata needed by measurement clients. "
"Its ``run`` method must take a `~lsst.verify.Job` as its first "
"parameter, and should accept unknown keyword arguments. It must "
"return a `~lsst.pipe.base.Struct` with the field ``job`` "
"pointing to the modified job.",
)


class MetricsControllerTask(Task):
Expand Down Expand Up @@ -109,6 +117,7 @@ def _makeTimingTask(self, target, metric):

def __init__(self, config=None, **kwargs):
super().__init__(config=config, **kwargs)
self.makeSubtask("metadataAdder")

# TODO: generalize in DM-16535
self.measurers = [
Expand Down Expand Up @@ -213,9 +222,7 @@ def runDataRefs(self, datarefs):
for dataref in datarefs:
job = Job.load_metrics_package()
try:
# TODO: generalize this in DM-16642
metadataAdder = SquashMetadataTask()
metadataAdder.run(job, dataref=dataref)
self.metadataAdder.run(job, dataref=dataref)

for task in self.measurers:
self._computeSingleMeasurement(job, task, dataref)
Expand Down
54 changes: 28 additions & 26 deletions tests/test_metricsController.py
Expand Up @@ -25,9 +25,8 @@
from astropy.tests.helper import assert_quantity_allclose

import lsst.utils.tests
from lsst.daf.persistence import ButlerDataRef
from lsst.afw.cameraGeom import Camera
from lsst.pipe.base import Struct
from lsst.pex.config import Config
from lsst.pipe.base import Task, Struct
from lsst.verify import Job, MetricComputationError
from lsst.verify.compatibility import MetricTask, MetricsControllerTask

Expand All @@ -38,21 +37,26 @@ def _metricName():
return "misc_tasks.FancyMetric"


# TODO: can be replaced with a vanilla mock after DM-16642
def _makeMockDataref(_datasetType, dataId=None):
"""A dataref-like object that returns a mock camera.
def _makeMockDataref(dataId=None):
"""A dataref-like object with a specific data ID.
"""
camera = unittest.mock.NonCallableMock(
Camera, autospec=True, **{"getName.return_value": "fancyCam"})
return unittest.mock.NonCallableMock(
ButlerDataRef, autospec=True, **{"get.return_value": camera},
dataId=dataId)
return unittest.mock.NonCallableMock(dataId=dataId)


def _butlerQuery(_butler, datasetType, _level="", dataId=None):
class _TestMetadataAdder(Task):
"""Simplest valid non-identity metadata adder.
"""
ConfigClass = Config

def run(self, job, **kwargs):
job.meta["tested"] = True
return Struct(job=job)


def _butlerQuery(_butler, _datasetType, _level="", dataId=None):
"""Return a number of datarefs corresponding to a (partial) dataId.
"""
dataref = _makeMockDataref(datasetType)
dataref = _makeMockDataref()

# Simulate a dataset of 3 visits and 2 CCDs
nRuns = 1
Expand All @@ -70,7 +74,9 @@ def _butlerQuery(_butler, datasetType, _level="", dataId=None):
class MetricsControllerTestSuite(lsst.utils.tests.TestCase):

def setUp(self):
self.task = MetricsControllerTask()
controllerConfig = MetricsControllerTask.ConfigClass()
controllerConfig.metadataAdder.retarget(_TestMetadataAdder)
self.task = MetricsControllerTask(controllerConfig)

self.metricTask = unittest.mock.create_autospec(
MetricTask, instance=True)
Expand Down Expand Up @@ -106,14 +112,12 @@ def _checkMetric(self, mockWriter, datarefs, unitsOfWork):

jobs = self.task.runDataRefs(datarefs).jobs
self.assertEqual(len(jobs), len(datarefs))
for job, dataref, nTimings in zip(jobs, datarefs, unitsOfWork):
for job, nTimings in zip(jobs, unitsOfWork):
self.assertEqual(len(job.measurements), 1)
assert_quantity_allclose(
job.measurements[_metricName()].quantity,
float(nTimings) * u.second)
self.assertEqual(job.meta["instrument"], "FANCYCAM")
for key in dataref.dataId:
self.assertEqual(job.meta[key], dataref.dataId[key])
self.assertTrue(job.meta["tested"])

# Exact arguments to Job.write are implementation detail, don't test
if not jobs:
Expand All @@ -126,27 +130,26 @@ def _checkMetric(self, mockWriter, datarefs, unitsOfWork):
def testCcdGrainedMetric(self, mockWriter, _mockButler,
_mockMetricsLoader):
dataId = {"visit": 42, "ccd": 101, "filter": "k"}
datarefs = [_makeMockDataref("calexp", dataId=dataId)]
datarefs = [_makeMockDataref(dataId)]
self._checkMetric(mockWriter, datarefs, unitsOfWork=[1])

def testVisitGrainedMetric(self, mockWriter, _mockButler,
_mockMetricsLoader):
dataId = {"visit": 42, "filter": "k"}
datarefs = [_makeMockDataref("calexp", dataId=dataId)]
datarefs = [_makeMockDataref(dataId)]
self._checkMetric(mockWriter, datarefs, unitsOfWork=[2])

def testDatasetGrainedMetric(self, mockWriter, _mockButler,
_mockMetricsLoader):
dataId = {}
datarefs = [_makeMockDataref("calexp", dataId=dataId)]
datarefs = [_makeMockDataref(dataId)]
self._checkMetric(mockWriter, datarefs, unitsOfWork=[6])

def testMultipleMetrics(self, mockWriter, _mockButler,
_mockMetricsLoader):
dataIds = [{"visit": 42, "ccd": 101, "filter": "k"},
{"visit": 42, "ccd": 102, "filter": "k"}]
datarefs = [_makeMockDataref("calexp", dataId=dataId)
for dataId in dataIds]
datarefs = [_makeMockDataref(dataId) for dataId in dataIds]
self._checkMetric(mockWriter, datarefs,
unitsOfWork=[1] * len(dataIds))

Expand All @@ -160,15 +163,14 @@ def testInvalidMetricSegregation(self, _mockWriter, _mockButler,

dataIds = [{"visit": 42, "ccd": 101, "filter": "k"},
{"visit": 42, "ccd": 102, "filter": "k"}]
datarefs = [_makeMockDataref("calexp", dataId=dataId)
for dataId in dataIds]
datarefs = [_makeMockDataref(dataId) for dataId in dataIds]

jobs = self.task.runDataRefs(datarefs).jobs
self.assertEqual(len(jobs), len(datarefs))

self.assertEqual(len(jobs[0].measurements), 0)
for job in jobs:
self.assertEqual(job.meta["instrument"], "FANCYCAM")
self.assertTrue(job.meta["tested"])
for job in jobs[1:]:
self.assertEqual(len(job.measurements), 1)
assert_quantity_allclose(
Expand Down

0 comments on commit 004b440

Please sign in to comment.