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-26684: Add command-line tool for Butler.pruneCollection #373

Merged
merged 3 commits into from
Sep 16, 2020
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
16 changes: 13 additions & 3 deletions python/lsst/daf/butler/cli/cmd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,19 @@
# 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__ = ["butler_import", "create", "config_dump", "config_validate", "query_collections",
"query_dataset_types"]
__all__ = ("butler_import",
"create",
"config_dump",
"config_validate",
"prune_collection",
"query_collections",
"query_dataset_types")


from .commands import (butler_import, create, config_dump, config_validate, query_collections,
from .commands import (butler_import,
create,
config_dump,
config_validate,
prune_collection,
query_collections,
query_dataset_types)
26 changes: 23 additions & 3 deletions python/lsst/daf/butler/cli/cmd/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@

from ..opt import (collection_type_option, dataset_type_option, directory_argument, glob_argument,
repo_argument, run_option, transfer_option, verbose_option)
from ..utils import split_commas, cli_handle_exception, typeStrAcceptsMultiple
from ...script import (butlerImport, createRepo, configDump, configValidate, queryCollections,
queryDatasetTypes)
from ..utils import cli_handle_exception, split_commas, typeStrAcceptsMultiple, unwrap
from ...script import (butlerImport, createRepo, configDump, configValidate, pruneCollection,
queryCollections, queryDatasetTypes)

willCreateRepoHelp = "REPO is the URI or path to the new repository. Will be created if it does not exist."
existingRepoHelp = "REPO is the URI or path to an existing data repository root or configuration file."
Expand Down Expand Up @@ -100,6 +100,26 @@ def config_validate(*args, **kwargs):
raise click.exceptions.Exit(1)


@click.command()
@repo_argument(required=True)
@click.option("--collection",
help=unwrap("""Name of the collection to remove. If this is a TAGGED or CHAINED collection,
datasets within the collection are not modified unless --unstore is passed. If this
is a RUN collection, --purge and --unstore must be passed, and all datasets in it
are fully removed from the data repository. """))
@click.option("--purge",
help=unwrap("""Permit RUN collections to be removed, fully removing datasets within them.
Requires --unstore as an added precaution against accidental deletion. Must not be
passed if the collection is not a RUN."""),
is_flag=True)
@click.option("--unstore",
help=("""Remove all datasets in the collection from all datastores in which they appear."""),
is_flag=True)
def prune_collection(**kwargs):
"""Remove a collection and possibly prune datasets within it."""
cli_handle_exception(pruneCollection, **kwargs)


@click.command(short_help="Search for collections.")
@repo_argument(required=True)
@glob_argument(help="GLOB is one or more glob-style expressions that fully or partially identify the "
Expand Down
1 change: 1 addition & 0 deletions python/lsst/daf/butler/script/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@
from .createRepo import createRepo
from .configDump import configDump
from .configValidate import configValidate
from .pruneCollection import pruneCollection
from .queryCollections import queryCollections
from .queryDatasetTypes import queryDatasetTypes
40 changes: 40 additions & 0 deletions python/lsst/daf/butler/script/pruneCollection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 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/>.

from .. import Butler


def pruneCollection(repo, collection, purge, unstore):
"""Remove a collection and possibly prune datasets within it.

Parameters
----------
repo : `str`
Same as the ``config`` argument to ``Butler.__init__``
collection : `str`
Same as the ``name`` argument to ``Butler.pruneCollection``.
purge : `bool`, optional
Same as the ``purge`` argument to ``Butler.pruneCollection``.
unstore: `bool`, optional
Same as the ``unstore`` argument to ``Butler.pruneCollection``.
"""
butler = Butler(repo, writeable=True)
butler.pruneCollection(collection, purge, unstore)
77 changes: 77 additions & 0 deletions tests/test_cliCmdPruneCollection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 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/>.

"""Unit tests for daf_butler CLI prune-collections subcommand.
"""

import unittest

import lsst.daf.butler
from lsst.daf.butler.cli.butler import cli as butlerCli
from lsst.daf.butler.cli.utils import clickResultMsg, LogCliRunner


class PruneCollectionsTest(unittest.TestCase):

def setUp(self):
self.runner = LogCliRunner()

def testPruneCollections(self):
"""Test removing a collection and run from a repository using the
butler prune-collection subcommand."""
with self.runner.isolated_filesystem():
repoName = "myRepo"
runName = "myRun"
taggedName = "taggedCollection"

# Add the run and the tagged collection to the repo:
result = self.runner.invoke(butlerCli, ["create", repoName])
self.assertEqual(result.exit_code, 0, clickResultMsg(result))
lsst.daf.butler.Butler(repoName, run=runName, tags=[taggedName])

# Verify the run and tag show up in query-collections:
result = self.runner.invoke(butlerCli, ["query-collections", repoName])
self.assertEqual(result.exit_code, 0, clickResultMsg(result))
self.assertIn(runName, result.output)
self.assertIn(taggedName, result.output)

# Verify the tagged collection can be removed:
result = self.runner.invoke(butlerCli, ["prune-collection", repoName,
"--collection", taggedName,
"--unstore"])
self.assertEqual(result.exit_code, 0, clickResultMsg(result))
result = self.runner.invoke(butlerCli, ["query-collections", repoName])
self.assertEqual(result.exit_code, 0, clickResultMsg(result))
self.assertIn(runName, result.output)
self.assertNotIn(taggedName, result.output)

# Verify the run can be removed:
result = self.runner.invoke(butlerCli, ["prune-collection", repoName,
"--collection", runName,
"--purge",
"--unstore"])
self.assertEqual(result.exit_code, 0, clickResultMsg(result))
self.assertNotIn(runName, result.output)
self.assertNotIn(taggedName, result.output)


if __name__ == "__main__":
unittest.main()