Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-14114: Add interface for camera specialization #31

Merged
merged 2 commits into from
Apr 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 0 additions & 13 deletions python/lsst/daf/butler/core/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,19 +251,6 @@ def markInputUsed(self, quantum, ref):
"""
raise NotImplementedError("Must be implemented by subclass")

@abstractmethod
def addDataUnit(self, unit, replace=False):
"""Add a new `DataUnit`, optionally replacing an existing one
(for updates).

unit : `DataUnit`
The `DataUnit` to add or replace.
replace : `bool`
If `True`, replace any matching `DataUnit` that already exists
(updating its non-unique fields) instead of raising an exception.
"""
raise NotImplementedError("Must be implemented by subclass")

@abstractmethod
def findDataUnit(self, cls, values):
"""Return a `DataUnit` given a dictionary of values.
Expand Down
70 changes: 70 additions & 0 deletions python/lsst/daf/butler/instrument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This file is part of daf_butler.
#
# Developed for the LSST Data Management System.
# This product includes software developed by the LSST Project
# (http://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.


__all__ = ("Instrument", )


class Instrument:
"""A template method class that can register itself with a
`Registry.

This class should be subclassed by various implementations.
Subclasses should provide all relevant attributes, as documented
below.

Attributes
----------
camera : `str`
Name of the camera. Must be provided by subclass.
physicalFilters : `list`
List of PhysicalFilter entries (each entry being a dict).
sensors : `list`
List of Sensor entries (each entry being a dict).
"""
camera = None
physicalFilters = []
sensors = []

def register(self, registry):
"""Register an instance of this `Instrument` with a `Registry`.

Creates all relevant `DataUnit` entries.
"""
assert self.camera is not None
self._addCamera(registry)
self._addPhysicalFilters(registry)
self._addSensors(registry)

def _addCamera(self, registry):
registry.addDataUnitEntry('Camera', {'camera': self.camera})

def _addPhysicalFilters(self, registry):
for entry in self.physicalFilters:
if 'camera' not in entry:
entry['camera'] = self.camera
registry.addDataUnitEntry('PhysicalFilter', entry)

def _addSensors(self, registry):
for entry in self.sensors:
if 'camera' not in entry:
entry['camera'] = self.camera
registry.addDataUnitEntry('Sensor', entry)
28 changes: 19 additions & 9 deletions python/lsst/daf/butler/registries/sqlRegistry.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from sqlalchemy import create_engine
from sqlalchemy.sql import select, and_, exists
from sqlalchemy.exc import IntegrityError

from ..core.datasets import DatasetType, DatasetRef
from ..core.registry import RegistryConfig, Registry
Expand Down Expand Up @@ -672,17 +673,26 @@ def markInputUsed(self, quantum, ref):
raise KeyError("{} is not a predicted consumer for {}".format(ref, quantum))
quantum._markInputUsed(ref)

def addDataUnit(self, unit, replace=False):
"""Add a new `DataUnit`, optionally replacing an existing one
(for updates).
def addDataUnitEntry(self, dataUnitName, values):
"""Add a new `DataUnit` entry.

unit : `DataUnit`
The `DataUnit` to add or replace.
replace : `bool`
If `True`, replace any matching `DataUnit` that already exists
(updating its non-unique fields) instead of raising an exception.
dataUnitName : `str`
Name of the `DataUnit` (e.g. ``"Camera"``).
values : `dict`
Dictionary of ``columnName, columnValue`` pairs.

Raises
------
ValueError
If an entry with the primary-key defined in `values` is already
present.
"""
raise NotImplementedError("Must be implemented by subclass")
dataUnitTable = self._schema.metadata.tables[dataUnitName]
with self._engine.begin() as connection:
try:
connection.execute(dataUnitTable.insert().values(**values))
except IntegrityError as err:
raise ValueError(str(err)) # TODO this should do an explicit validity check instead

def findDataUnit(self, cls, values):
"""Return a `DataUnit` given a dictionary of values.
Expand Down
69 changes: 69 additions & 0 deletions tests/test_instrument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# This file is part of daf_butler.
#
# Developed for the LSST Data Management System.
# This product includes software developed by the LSST Project
# (http://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import os
import unittest

import lsst.utils.tests

from lsst.daf.butler.core import Registry

from lsst.daf.butler.instrument import Instrument

"""Tests for Instrument.
"""


class DummyCam(Instrument):
camera = 'DummyCam'

physicalFilters = [{'physical_filter': 'dummy_g'},
{'physical_filter': 'dummy_u'}]

sensors = [{'sensor': 'one'},
{'sensor': 'two'}]


class InstrumentTestCase(lsst.utils.tests.TestCase):
"""Test for Instrument.
"""

def setUp(self):
self.testDir = os.path.dirname(__file__)
self.configFile = os.path.join(self.testDir, "config/basic/butler.yaml")

def testRegister(self):
registry = Registry.fromConfig(self.configFile)
dummyCam = DummyCam()
dummyCam.register(registry)


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


def setup_module(module):
lsst.utils.tests.init()


if __name__ == "__main__":
lsst.utils.tests.init()
unittest.main()
9 changes: 9 additions & 0 deletions tests/test_sqlRegistry.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,15 @@ def testCollections(self):
outputRef = registry.find(newCollection, datasetType, dataId2)
self.assertEqual(outputRef, inputRef2)

def testDatasetUnit(self):
registry = Registry.fromConfig(self.configFile)
dataUnitName = 'Camera'
dataUnitValue = {'camera': 'DummyCam'}
registry.addDataUnitEntry(dataUnitName, dataUnitValue)
# Inserting the same value twice should fail
with self.assertRaises(ValueError):
registry.addDataUnitEntry(dataUnitName, dataUnitValue)


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