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-24584: create an ingestRaws butler command #241

Merged
merged 13 commits into from
May 13, 2020
39 changes: 28 additions & 11 deletions python/lsst/obs/base/cli/butler_cmd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,41 @@ class ButlerCmdTestBase(metaclass=abc.ABCMeta):
Subclass from this, then `unittest.TestCase` to get a working test suite.
"""

instrument_class = None
"""The fully qualified instrument class.
"""
@staticmethod
@abc.abstractmethod
def instrumentClass():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These do indeed force a test implementation to specify the value but in most cases the tests will fail if they do it wrong. It's a shame that a subclass can't implement by doing a simple class property but the use of static method here prevents that.

Also instrumentClass as a name makes you think this is the class but it's not, it's the class name.

"""Get the fully qualified instrument class.

Returns
-------
`str`
The fully qualified instrument class.
"""
pass

@staticmethod
@abc.abstractmethod
def instrumentName():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the Instrument class itself defines the name, wouldn't it be easier for everyone if a subclass could specify an Instrument class directly (not a string, although a string could be doImported) and the name was retrieve from that directly? It would prevent an obvious case of duplication of information in the tests where the test subclass now needs to specify the name and the class name and ensure that they all match with the name that they already know is defined in the Instrument class.

"""Get the instrument name.

instrument_name = None
"""The instrument name."""
Returns
-------
`str`
The name of the instrument.
"""
pass

def test_cli(self):
runner = click.testing.CliRunner()
with runner.isolated_filesystem():
result = runner.invoke(butler.cli, ["create", "here"])
self.assertEqual(result.exit_code, 0, result.output)
self.assertEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}")
result = runner.invoke(butler.cli, ["register-instrument",
"here",
"-i", self.instrument_class])
self.assertEqual(result.exit_code, 0, result.output)
"-i", self.instrumentClass()])
self.assertEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}")
result = runner.invoke(butler.cli, ["write-curated-calibrations",
"here",
"-i", self.instrument_name,
"--output-run", "calib/hsc"])
self.assertEqual(result.exit_code, 0, result.output)
"-i", self.instrumentName(),
"--output-run", "output_run"])
self.assertEqual(result.exit_code, 0, f"output: {result.output} exception: {result.exception}")
1 change: 1 addition & 0 deletions python/lsst/obs/base/cli/cmd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@

from .register_instrument import register_instrument
from .write_curated_calibrations import write_curated_calibrations
from .ingest_raws import ingest_raws
41 changes: 41 additions & 0 deletions python/lsst/obs/base/cli/cmd/ingest_raws.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# This file is part of obs_base.
#
# 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 click

from lsst.daf.butler.cli.opt import repo_argument, config_option, config_file_option, run_option
from lsst.daf.butler.cli.utils import cli_handle_exception
from ...script import ingestRaws


@click.command()
@repo_argument(required=True)
@config_option()
@config_file_option()
@run_option(required=True)
@click.option("-d", "--dir", "directory",
help="The path to the directory containing the raws to ingest.")
@click.option("-f", "--file", help="The name of a file containing raws to ingest.")
@click.option("-t", "--transfer", help="The external data transfer type.", default="auto")
@click.option("--ingest-task", default="lsst.obs.base.RawIngestTask", help="The fully qualified class name "
"of the ingest task to use.")
def ingest_raws(*args, **kwargs):
cli_handle_exception(ingestRaws, *args, **kwargs)
22 changes: 5 additions & 17 deletions python/lsst/obs/base/cli/cmd/register_instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import click
import logging

from lsst.daf.butler.cli.opt import repo_argument
from lsst.daf.butler import Butler
from lsst.daf.butler.cli.utils import cli_handle_exception
from ..opt import instrument_option
from ...utils import getInstrument

log = logging.getLogger(__name__)
from ...script import registerInstrument


@click.command()
@repo_argument(required=True)
@instrument_option(required=True, helpMsg="The fully-qualified name of an Instrument subclass.")
@click.pass_context
def register_instrument(context, repo, instrument):
@instrument_option(required=True, help="The fully-qualified name of an Instrument subclass.")
def register_instrument(*args, **kwargs):
"""Add an instrument to the data repository.
"""
butler = Butler(repo, writeable=True)
try:
instr = getInstrument(instrument, butler.registry)
except RuntimeError as err:
log.critical("Failed getting instrument %s with exception %s", instrument, err)
raise click.ClickException("Could not import instrument.")
except TypeError:
raise click.ClickException(f"{instrument} is not a subclass of obs.base.Instrument")
instr.register(butler.registry)
cli_handle_exception(registerInstrument, *args, **kwargs)
21 changes: 4 additions & 17 deletions python/lsst/obs/base/cli/cmd/write_curated_calibrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import click
import logging

from lsst.daf.butler.cli.opt import repo_argument, run_option
from lsst.daf.butler import Butler
from lsst.daf.butler.cli.utils import cli_handle_exception
from ..opt import instrument_option
from ...utils import getInstrument

log = logging.getLogger(__name__)
from ...script import writeCuratedCalibrations


@click.command()
@repo_argument(required=True)
@instrument_option(required=True)
@run_option(required=True)
@click.pass_context
def write_curated_calibrations(context, repo, instrument, output_run):
def write_curated_calibrations(*args, **kwargs):
"""Add an instrument's curated calibrations to the data repository.
"""
butler = Butler(repo, writeable=True, run=output_run)
try:
instr = getInstrument(instrument, butler.registry)
except RuntimeError as err:
log.critical(f"Exception getting instrument: {err}")
raise click.BadParameter(f"Failed getting instrument {instrument} from repo {repo}")
except TypeError as err:
log.critical(f"{instrument} is not an Instrument subclass. {err}")
raise click.BadParameter(f"{instrument} is not an Instrument subclass.")
instr.writeCuratedCalibrations(butler)
cli_handle_exception(writeCuratedCalibrations, *args, **kwargs)
4 changes: 2 additions & 2 deletions python/lsst/obs/base/cli/opt/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@


class instrument_option: # noqa: N801
def __init__(self, required=False, helpMsg=None):
def __init__(self, required=False, help=None):
self.required = required
self.help = "The name or fully-qualified class name of an instrument." if helpMsg is None else helpMsg
self.help = "The name or fully-qualified class name of an instrument." if help is None else help

def __call__(self, f):
return click.option("-i", "--instrument",
Expand Down
1 change: 1 addition & 0 deletions python/lsst/obs/base/cli/resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ cmd:
commands:
- register-instrument
- write-curated-calibrations
- ingest-raws