Coverage for tests/test_cmdLineParser.py : 15%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of ctrl_mpexec.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://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 program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22"""Simple unit test for parser module.
23"""
25from argparse import ArgumentParser
26import unittest
28import lsst.utils.tests
29from lsst.daf.butler import CollectionSearch
30import lsst.ctrl.mpexec.cmdLineParser as parser_mod
33class _Error(Exception):
34 pass
37class _NoExitParser(ArgumentParser):
38 """Special parser subclass which does not exit on errors or help.
39 """
41 def exit(self, status=0, message=None):
42 pass
44 def error(self, message):
45 raise _Error(message)
48class CmdLineParserTestCase(unittest.TestCase):
49 """A test case for parser module
50 """
52 def setUp(self):
53 pass
55 def tearDown(self):
56 pass
58 def testPipelineAction(self):
59 """Test for a _PipelineAction and _pipe_action
60 """
62 parser = _NoExitParser()
63 parser.add_argument("-t", dest="pipeline_actions", action='append',
64 type=parser_mod._ACTION_ADD_TASK)
66 PipelineAction = parser_mod._PipelineAction
67 args = parser.parse_args("-t task".split())
68 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "task")])
70 args = parser.parse_args("-t task:label".split())
71 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", "label", "task")])
73 args = parser.parse_args("-t task".split())
74 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "task")])
76 # something that is not syntaxically correct (not a literal)
77 with self.assertRaises(_Error):
78 parser.parse_args("-t task -s task:CannotEval".split())
80 # Literal but of the wrong type
81 with self.assertRaises(_Error):
82 parser.parse_args("-t task -s task:[1,2]".split())
84 # dictionary but not all strings
85 with self.assertRaises(_Error):
86 parser.parse_args("-t task -s task:{'x':1}".split())
88 def testInputCollectionAction(self):
89 """Test for a _InputCollectionAction
90 """
92 parser = _NoExitParser()
93 parser.add_argument("-i", dest="input", action=parser_mod._InputCollectionAction, default=[])
95 args = parser.parse_args("".split())
97 def assertExpressionsEquivalent(a, b):
98 """Test that input collection expressions are equivalent after
99 being standardized by CollectionSearch.fromExpression.
100 """
101 self.assertEqual(CollectionSearch.fromExpression(a), CollectionSearch.fromExpression(b))
103 assertExpressionsEquivalent(args.input, [])
105 args = parser.parse_args("-i coll".split())
106 assertExpressionsEquivalent(args.input, ["coll"])
108 # collection can appear twice
109 args = parser.parse_args("-i coll,coll".split())
110 assertExpressionsEquivalent(args.input, ["coll"])
112 args = parser.parse_args("-i coll1,coll2,coll3".split())
113 assertExpressionsEquivalent(args.input, ["coll1", "coll2", "coll3"])
115 args = parser.parse_args("-i coll1 -i coll2 -i coll3".split())
116 assertExpressionsEquivalent(args.input, ["coll1", "coll2", "coll3"])
118 args = parser.parse_args("-i coll1 -i coll2,coll3".split())
119 assertExpressionsEquivalent(args.input, ["coll1", "coll2", "coll3"])
121 args = parser.parse_args("-i coll1 -i coll2 -i coll3".split())
122 assertExpressionsEquivalent(args.input, ["coll1", "coll2", "coll3"])
124 args = parser.parse_args("-i ds:coll".split())
125 assertExpressionsEquivalent(args.input, [("coll", "ds")])
127 args = parser.parse_args("-i ds1:coll1,ds2:coll2,ds2:coll3".split())
128 assertExpressionsEquivalent(args.input, [("coll1", "ds1"), ("coll2", "ds2"), ("coll3", "ds2")])
130 args = parser.parse_args("-i coll1,coll2,ds1:coll1,ds2:coll2,coll3".split())
131 assertExpressionsEquivalent(args.input, ["coll1", "coll2",
132 ("coll1", "ds1"), ("coll2", "ds2"),
133 "coll3"])
135 args = parser.parse_args("-i coll1 -i coll2 -i ds1:coll1 -i ds2:coll2 -i coll3".split())
136 assertExpressionsEquivalent(args.input, ["coll1", "coll2",
137 ("coll1", "ds1"), ("coll2", "ds2"),
138 "coll3"])
140 # use non-empty default
141 parser = _NoExitParser()
142 parser.add_argument("-i", dest="input", action=parser_mod._InputCollectionAction,
143 default=[("coll", ...)])
145 args = parser.parse_args("".split())
146 assertExpressionsEquivalent(args.input, ["coll"])
148 args = parser.parse_args("-i coll".split())
149 assertExpressionsEquivalent(args.input, ["coll"])
151 args = parser.parse_args("-i coll1 -i coll2 -i coll3".split())
152 assertExpressionsEquivalent(args.input, ["coll", "coll1", "coll2", "coll3"])
154 def testCmdLineParser(self):
155 """Test for parser_mod.CmdLineParser
156 """
157 parser = parser_mod.makeParser(parser_class=_NoExitParser)
159 # this should result in error
160 self.assertRaises(_Error, parser.parse_args)
162 # know attributes to appear in parser output for all subcommands
163 common_options = "loglevel longlog enableLsstDebug subcommand subparser".split()
165 # test for the set of options defined in each command
166 args = parser.parse_args(
167 """
168 build -t cmd
169 """.split())
170 build_options = """pipeline pipeline_actions order_pipeline
171 save_pipeline pipeline_dot show""".split()
172 self.assertEqual(set(vars(args).keys()), set(common_options + build_options))
173 self.assertEqual(args.subcommand, 'build')
175 args = parser.parse_args(
176 """
177 qgraph -t cmd
178 """.split())
179 qgraph_options = build_options + """qgraph data_query butler_config
180 input output skip_existing output_run extend_run
181 replace_run prune_replaced
182 save_qgraph qgraph_dot save_single_quanta""".split()
183 self.assertEqual(set(vars(args).keys()), set(common_options + qgraph_options))
184 self.assertEqual(args.subcommand, 'qgraph')
186 args = parser.parse_args(
187 """
188 run -t taskname
189 """.split())
190 run_options = qgraph_options + """register_dataset_types skip_init_writes
191 init_only processes profile timeout doraise graph_fixup
192 no_versions""".split()
193 self.assertEqual(set(vars(args).keys()), set(common_options + run_options))
194 self.assertEqual(args.subcommand, 'run')
196 def testCmdLineTasks(self):
198 parser = parser_mod.makeParser(parser_class=_NoExitParser)
200 PipelineAction = parser_mod._PipelineAction
202 # default options
203 args = parser.parse_args(
204 """
205 run -t taskname
206 """.split())
207 self.assertFalse(args.enableLsstDebug)
208 self.assertFalse(args.doraise)
209 self.assertEqual(args.input, [])
210 self.assertEqual(args.loglevel, [])
211 self.assertFalse(args.longlog)
212 self.assertEqual(args.output, None)
213 self.assertEqual(args.output_run, None)
214 self.assertEqual(args.extend_run, False)
215 self.assertEqual(args.replace_run, False)
216 self.assertEqual(args.processes, 1)
217 self.assertIsNone(args.profile)
218 self.assertIsNone(args.timeout)
219 self.assertIsNone(args.graph_fixup)
220 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "taskname")])
221 self.assertEqual(args.show, [])
222 self.assertIsNotNone(args.subparser)
223 self.assertIsNone(args.pipeline)
225 # bunch of random options
226 args = parser.parse_args(
227 """
228 run
229 --debug
230 --doraise
231 --input inputColl
232 --loglevel DEBUG -L component=trace
233 --longlog
234 --output outputColl
235 -j 66
236 --profile profile.out
237 --timeout 10.10
238 -t taskname:label
239 --show config
240 --show config=Task.*
241 -c label:a=b
242 -C label:filename1
243 -c label:c=d -c label:e=f
244 -C label:filename2 -C label:filename3
245 --skip-existing
246 """.split())
247 self.assertTrue(args.enableLsstDebug)
248 self.assertTrue(args.doraise)
249 self.assertEqual(args.input, [("inputColl", ...)])
250 self.assertEqual(args.loglevel, [(None, 'DEBUG'), ('component', 'TRACE')])
251 self.assertTrue(args.longlog)
252 self.assertEqual(args.output, "outputColl")
253 self.assertEqual(args.processes, 66)
254 self.assertEqual(args.profile, 'profile.out')
255 self.assertEqual(args.timeout, 10.10)
256 self.assertIsNone(args.graph_fixup)
257 self.assertEqual(args.show, ['config', 'config=Task.*'])
258 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", "label", "taskname"),
259 PipelineAction("config", "label", "a=b"),
260 PipelineAction("configfile", "label", "filename1"),
261 PipelineAction("config", "label", "c=d"),
262 PipelineAction("config", "label", "e=f"),
263 PipelineAction("configfile", "label", "filename2"),
264 PipelineAction("configfile", "label", "filename3")])
265 self.assertIsNone(args.pipeline)
266 self.assertIsNone(args.qgraph)
267 self.assertFalse(args.order_pipeline)
268 self.assertIsNone(args.save_pipeline)
269 self.assertIsNone(args.save_qgraph)
270 self.assertIsNone(args.pipeline_dot)
271 self.assertIsNone(args.qgraph_dot)
272 self.assertTrue(args.skip_existing)
274 # multiple tasks plus more options (-q should be exclusive with
275 # some other options but we do not check it during parsing (yet))
276 args = parser.parse_args(
277 """
278 run
279 -p pipeline.yaml
280 -g qgraph.pickle
281 -t task1
282 -t task2:label2
283 -t task3
284 -t task4
285 --show config
286 -c task1:a=b
287 -C task1:filename1
288 -c label2:c=d -c label2:e=f
289 -C task3:filename2 -C task3:filename3
290 --show config=Task.*
291 -C task4:filename4 -c task4:x=y
292 --order-pipeline
293 --save-pipeline=newpipe.yaml
294 --save-qgraph=newqgraph.pickle
295 --pipeline-dot pipe.dot
296 --qgraph-dot qgraph.dot
297 --graph-fixup lsst.ctrl.mpexec.Fixup
298 """.split())
299 self.assertEqual(args.show, ['config', 'config=Task.*'])
300 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "task1"),
301 PipelineAction("new_task", "label2", "task2"),
302 PipelineAction("new_task", None, "task3"),
303 PipelineAction("new_task", None, "task4"),
304 PipelineAction("config", "task1", "a=b"),
305 PipelineAction("configfile", "task1", "filename1"),
306 PipelineAction("config", "label2", "c=d"),
307 PipelineAction("config", "label2", "e=f"),
308 PipelineAction("configfile", "task3", "filename2"),
309 PipelineAction("configfile", "task3", "filename3"),
310 PipelineAction("configfile", "task4", "filename4"),
311 PipelineAction("config", "task4", "x=y")])
312 self.assertEqual(args.pipeline, "pipeline.yaml")
313 self.assertEqual(args.qgraph, "qgraph.pickle")
314 self.assertTrue(args.order_pipeline)
315 self.assertEqual(args.save_pipeline, "newpipe.yaml")
316 self.assertEqual(args.save_qgraph, "newqgraph.pickle")
317 self.assertEqual(args.pipeline_dot, "pipe.dot")
318 self.assertEqual(args.qgraph_dot, "qgraph.dot")
319 self.assertEqual(args.graph_fixup, "lsst.ctrl.mpexec.Fixup")
321 def testCmdLinePipeline(self):
323 parser = parser_mod.makeParser(parser_class=_NoExitParser)
325 PipelineAction = parser_mod._PipelineAction
327 args = parser.parse_args(
328 """
329 run -p pipeline
330 --show config
331 --show config=Task.*
332 """.split())
333 self.assertEqual(args.show, ['config', 'config=Task.*'])
334 self.assertEqual(args.pipeline, 'pipeline')
335 self.assertEqual(args.pipeline_actions, [])
337 args = parser.parse_args("run -p pipeline -t task".split())
338 self.assertEqual(args.pipeline, 'pipeline')
339 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "task")])
342class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
343 pass
346def setup_module(module):
347 lsst.utils.tests.init()
350if __name__ == "__main__": 350 ↛ 351line 350 didn't jump to line 351, because the condition on line 350 was never true
351 lsst.utils.tests.init()
352 unittest.main()