Coverage for tests/test_cliCmdRemoveRuns.py: 14%
78 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-19 01:32 -0800
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-19 01:32 -0800
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
28"""Unit tests for daf_butler CLI remove-runs subcommand."""
30import os
31import unittest
33from lsst.daf.butler import DatasetType
34from lsst.daf.butler.cli import butler
35from lsst.daf.butler.cli.cmd._remove_runs import (
36 abortedMsg,
37 didRemoveDatasetsMsg,
38 didRemoveRunsMsg,
39 mustBeUnlinkedMsg,
40 noRunCollectionsMsg,
41 removedRunsMsg,
42 willRemoveDatasetsMsg,
43 willRemoveRunsMsg,
44 willUnlinkMsg,
45)
46from lsst.daf.butler.cli.utils import LogCliRunner, clickResultMsg
47from lsst.daf.butler.tests.utils import MetricTestRepo
49TESTDIR = os.path.abspath(os.path.dirname(__file__))
52class RemoveCollectionTest(unittest.TestCase):
53 """Test the butler remove-runs command."""
55 def setUp(self):
56 self.runner = LogCliRunner()
58 def test_removeRuns(self):
59 with self.runner.isolated_filesystem():
60 root = "repo"
61 repo = MetricTestRepo(root, configFile=os.path.join(TESTDIR, "config/basic/butler.yaml"))
62 # Add a dataset type that will have no datasets to make sure it
63 # isn't printed.
64 repo.butler.registry.registerDatasetType(
65 DatasetType("no_datasets", repo.butler.dimensions.empty, "StructuredDataDict")
66 )
68 # Execute remove-runs but say no, check for expected outputs.
69 result = self.runner.invoke(butler.cli, ["remove-runs", root, "ingest*"], input="no")
70 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
71 self.assertIn(willRemoveRunsMsg, result.output)
72 self.assertIn(abortedMsg, result.output)
73 self.assertNotIn("no_datasets", result.output)
74 self.assertIn(
75 "ingest/run",
76 list(repo.butler.registry.queryCollections()),
77 )
79 # Add the run to a CHAINED collection.
80 parentCollection = "aParentCollection"
81 result = self.runner.invoke(
82 butler.cli, f"collection-chain {root} {parentCollection} ingest/run".split()
83 )
84 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
85 result = self.runner.invoke(butler.cli, ["query-collections", root])
86 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
87 self.assertIn(parentCollection, result.output)
89 # Execute remove-runs but say no, check for expected outputs
90 # including the CHAINED collection.
91 result = self.runner.invoke(butler.cli, ["remove-runs", root, "ingest*"], input="no")
92 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
93 self.assertIn(willRemoveRunsMsg, result.output)
94 self.assertIn(willRemoveDatasetsMsg, result.output)
95 self.assertIn(
96 willUnlinkMsg.format(run="ingest/run", parents=f'"{parentCollection}"'), result.output
97 )
98 self.assertIn(abortedMsg, result.output)
99 self.assertNotIn("no_datasets", result.output)
100 result = self.runner.invoke(butler.cli, ["query-collections", root])
101 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
102 self.assertIn("ingest/run", result.output)
103 self.assertIn(parentCollection, result.output)
105 # Do the same remove-runs command, but say yes.
106 result = self.runner.invoke(butler.cli, ["remove-runs", root, "ingest*"], input="yes")
107 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
108 self.assertIn(willRemoveRunsMsg, result.output)
109 self.assertIn(willRemoveDatasetsMsg, result.output)
110 self.assertIn(removedRunsMsg, result.output)
111 result = self.runner.invoke(butler.cli, ["query-collections", root])
112 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
113 self.assertNotIn("ingest/run", result.output)
114 self.assertIn(parentCollection, result.output)
116 # Now they've been deleted, try again and check for "none found".
117 result = self.runner.invoke(butler.cli, ["remove-runs", root, "ingest*"])
118 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
119 self.assertIn(noRunCollectionsMsg, result.output)
121 # Remake the repo and check --no-confirm option.
122 root = "repo1"
123 MetricTestRepo(root, configFile=os.path.join(TESTDIR, "config/basic/butler.yaml"))
125 # Add the run to a CHAINED collection.
126 parentCollection = "parent"
127 result = self.runner.invoke(
128 butler.cli, f"collection-chain {root} {parentCollection} ingest/run".split()
129 )
130 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
131 result = self.runner.invoke(butler.cli, ["query-collections", root])
132 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
133 self.assertIn("ingest/run", result.output)
134 self.assertIn(parentCollection, result.output)
136 # Execute remove-runs with --no-confirm, should fail because there
137 # is a parent CHAINED collection.
138 result = self.runner.invoke(butler.cli, ["remove-runs", root, "ingest*", "--no-confirm"])
139 self.assertNotEqual(result.exit_code, 0, clickResultMsg(result))
140 self.assertIn(
141 mustBeUnlinkedMsg.format(run="ingest/run", parents=f'"{parentCollection}"'), result.output
142 )
143 result = self.runner.invoke(butler.cli, ["query-collections", root])
144 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
145 self.assertIn("ingest/run", result.output)
146 self.assertIn(parentCollection, result.output)
148 # Execute remove-runs with --no-confirm and --force
149 result = self.runner.invoke(
150 butler.cli, ["remove-runs", root, "ingest*", "--no-confirm", "--force"]
151 )
152 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
153 self.assertIn(didRemoveRunsMsg, result.output)
154 self.assertIn(didRemoveDatasetsMsg, result.output)
155 result = self.runner.invoke(butler.cli, ["query-collections", root])
156 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
157 self.assertNotIn("ingest/run", result.output)
158 self.assertIn(parentCollection, result.output)
160 # Execute cmd looking for a non-existant collection
161 result = self.runner.invoke(butler.cli, ["remove-runs", root, "foo"])
162 self.assertEqual(result.exit_code, 0, clickResultMsg(result))
163 self.assertIn(noRunCollectionsMsg, result.output)
166if __name__ == "__main__":
167 unittest.main()