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""".split()
192 self.assertEqual(set(vars(args).keys()), set(common_options + run_options))
193 self.assertEqual(args.subcommand, 'run')
195 def testCmdLineTasks(self):
197 parser = parser_mod.makeParser(parser_class=_NoExitParser)
199 PipelineAction = parser_mod._PipelineAction
201 # default options
202 args = parser.parse_args(
203 """
204 run -t taskname
205 """.split())
206 self.assertFalse(args.enableLsstDebug)
207 self.assertFalse(args.doraise)
208 self.assertEqual(args.input, [])
209 self.assertEqual(args.loglevel, [])
210 self.assertFalse(args.longlog)
211 self.assertEqual(args.output, None)
212 self.assertEqual(args.output_run, None)
213 self.assertEqual(args.extend_run, False)
214 self.assertEqual(args.replace_run, False)
215 self.assertEqual(args.processes, 1)
216 self.assertIsNone(args.profile)
217 self.assertIsNone(args.timeout)
218 self.assertIsNone(args.graph_fixup)
219 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "taskname")])
220 self.assertEqual(args.show, [])
221 self.assertIsNotNone(args.subparser)
222 self.assertIsNone(args.pipeline)
224 # bunch of random options
225 args = parser.parse_args(
226 """
227 run
228 --debug
229 --doraise
230 --input inputColl
231 --loglevel DEBUG -L component=trace
232 --longlog
233 --output outputColl
234 -j 66
235 --profile profile.out
236 --timeout 10.10
237 -t taskname:label
238 --show config
239 --show config=Task.*
240 -c label:a=b
241 -C label:filename1
242 -c label:c=d -c label:e=f
243 -C label:filename2 -C label:filename3
244 --skip-existing
245 """.split())
246 self.assertTrue(args.enableLsstDebug)
247 self.assertTrue(args.doraise)
248 self.assertEqual(args.input, [("inputColl", ...)])
249 self.assertEqual(args.loglevel, [(None, 'DEBUG'), ('component', 'TRACE')])
250 self.assertTrue(args.longlog)
251 self.assertEqual(args.output, "outputColl")
252 self.assertEqual(args.processes, 66)
253 self.assertEqual(args.profile, 'profile.out')
254 self.assertEqual(args.timeout, 10.10)
255 self.assertIsNone(args.graph_fixup)
256 self.assertEqual(args.show, ['config', 'config=Task.*'])
257 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", "label", "taskname"),
258 PipelineAction("config", "label", "a=b"),
259 PipelineAction("configfile", "label", "filename1"),
260 PipelineAction("config", "label", "c=d"),
261 PipelineAction("config", "label", "e=f"),
262 PipelineAction("configfile", "label", "filename2"),
263 PipelineAction("configfile", "label", "filename3")])
264 self.assertIsNone(args.pipeline)
265 self.assertIsNone(args.qgraph)
266 self.assertFalse(args.order_pipeline)
267 self.assertIsNone(args.save_pipeline)
268 self.assertIsNone(args.save_qgraph)
269 self.assertIsNone(args.pipeline_dot)
270 self.assertIsNone(args.qgraph_dot)
271 self.assertTrue(args.skip_existing)
273 # multiple tasks plus more options (-q should be exclusive with
274 # some other options but we do not check it during parsing (yet))
275 args = parser.parse_args(
276 """
277 run
278 -p pipeline.yaml
279 -g qgraph.pickle
280 -t task1
281 -t task2:label2
282 -t task3
283 -t task4
284 --show config
285 -c task1:a=b
286 -C task1:filename1
287 -c label2:c=d -c label2:e=f
288 -C task3:filename2 -C task3:filename3
289 --show config=Task.*
290 -C task4:filename4 -c task4:x=y
291 --order-pipeline
292 --save-pipeline=newpipe.yaml
293 --save-qgraph=newqgraph.pickle
294 --pipeline-dot pipe.dot
295 --qgraph-dot qgraph.dot
296 --graph-fixup lsst.ctrl.mpexec.Fixup
297 """.split())
298 self.assertEqual(args.show, ['config', 'config=Task.*'])
299 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "task1"),
300 PipelineAction("new_task", "label2", "task2"),
301 PipelineAction("new_task", None, "task3"),
302 PipelineAction("new_task", None, "task4"),
303 PipelineAction("config", "task1", "a=b"),
304 PipelineAction("configfile", "task1", "filename1"),
305 PipelineAction("config", "label2", "c=d"),
306 PipelineAction("config", "label2", "e=f"),
307 PipelineAction("configfile", "task3", "filename2"),
308 PipelineAction("configfile", "task3", "filename3"),
309 PipelineAction("configfile", "task4", "filename4"),
310 PipelineAction("config", "task4", "x=y")])
311 self.assertEqual(args.pipeline, "pipeline.yaml")
312 self.assertEqual(args.qgraph, "qgraph.pickle")
313 self.assertTrue(args.order_pipeline)
314 self.assertEqual(args.save_pipeline, "newpipe.yaml")
315 self.assertEqual(args.save_qgraph, "newqgraph.pickle")
316 self.assertEqual(args.pipeline_dot, "pipe.dot")
317 self.assertEqual(args.qgraph_dot, "qgraph.dot")
318 self.assertEqual(args.graph_fixup, "lsst.ctrl.mpexec.Fixup")
320 def testCmdLinePipeline(self):
322 parser = parser_mod.makeParser(parser_class=_NoExitParser)
324 PipelineAction = parser_mod._PipelineAction
326 args = parser.parse_args(
327 """
328 run -p pipeline
329 --show config
330 --show config=Task.*
331 """.split())
332 self.assertEqual(args.show, ['config', 'config=Task.*'])
333 self.assertEqual(args.pipeline, 'pipeline')
334 self.assertEqual(args.pipeline_actions, [])
336 args = parser.parse_args("run -p pipeline -t task".split())
337 self.assertEqual(args.pipeline, 'pipeline')
338 self.assertEqual(args.pipeline_actions, [PipelineAction("new_task", None, "task")])
341class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
342 pass
345def setup_module(module):
346 lsst.utils.tests.init()
349if __name__ == "__main__": 349 ↛ 350line 349 didn't jump to line 350, because the condition on line 349 was never true
350 lsst.utils.tests.init()
351 unittest.main()