Coverage for python/lsst/ctrl/mpexec/cli/cmd/commands.py: 68%

90 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-22 02:07 -0700

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# (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 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 <http://www.gnu.org/licenses/>. 

21 

22import sys 

23from functools import partial 

24from typing import Any 

25 

26import click 

27import lsst.pipe.base.cli.opt as pipeBaseOpts 

28from lsst.ctrl.mpexec.showInfo import ShowInfo 

29from lsst.daf.butler.cli.opt import config_file_option, config_option, confirm_option, options_file_option 

30from lsst.daf.butler.cli.utils import MWCtxObj, catch_and_exit, option_section, unwrap 

31 

32from .. import opt as ctrlMpExecOpts 

33from .. import script 

34from ..script import confirmable 

35from ..utils import _ACTION_CONFIG, _ACTION_CONFIG_FILE, PipetaskCommand, makePipelineActions 

36 

37epilog = unwrap( 

38 """Notes: 

39 

40--task, --delete, --config, --config-file, and --instrument action options can 

41appear multiple times; all values are used, in order left to right. 

42 

43FILE reads command-line options from the specified file. Data may be 

44distributed among multiple lines (e.g. one option per line). Data after # is 

45treated as a comment and ignored. Blank lines and lines starting with # are 

46ignored.) 

47""" 

48) 

49 

50 

51def _collectActions(ctx: click.Context, **kwargs: Any) -> dict[str, Any]: 

52 """Extract pipeline building options, replace them with PipelineActions, 

53 return updated `kwargs`. 

54 

55 Notes 

56 ----- 

57 The pipeline actions (task, delete, config, config_file, and instrument) 

58 must be handled in the order they appear on the command line, but the CLI 

59 specification gives them all different option names. So, instead of using 

60 the individual action options as they appear in kwargs (because 

61 invocation order can't be known), we capture the CLI arguments by 

62 overriding `click.Command.parse_args` and save them in the Context's 

63 `obj` parameter. We use `makePipelineActions` to create a list of 

64 pipeline actions from the CLI arguments and pass that list to the script 

65 function using the `pipeline_actions` kwarg name, and remove the action 

66 options from kwargs. 

67 """ 

68 for pipelineAction in ( 

69 ctrlMpExecOpts.task_option.name(), 

70 ctrlMpExecOpts.delete_option.name(), 

71 config_option.name(), 

72 config_file_option.name(), 

73 pipeBaseOpts.instrument_option.name(), 

74 ): 

75 kwargs.pop(pipelineAction) 

76 

77 actions = makePipelineActions(MWCtxObj.getFrom(ctx).args) 

78 mock_configs = [] 

79 pipeline_actions = [] 

80 for action in actions: 

81 if action.label and action.label.endswith("-mock"): 81 ↛ 82line 81 didn't jump to line 82, because the condition on line 81 was never true

82 if action.action not in (_ACTION_CONFIG.action, _ACTION_CONFIG_FILE.action): 

83 raise ValueError(f"Unexpected option for mock task config overrides: {action}") 

84 mock_configs.append(action) 

85 else: 

86 pipeline_actions.append(action) 

87 

88 kwargs["mock_configs"] = mock_configs 

89 kwargs["pipeline_actions"] = pipeline_actions 

90 return kwargs 

91 

92 

93def _unhandledShow(show: ShowInfo, cmd: str) -> None: 

94 if show.unhandled: 94 ↛ 95line 94 didn't jump to line 95, because the condition on line 94 was never true

95 print( 

96 f"The following '--show' options were not known to the {cmd} command: " 

97 f"{', '.join(show.unhandled)}", 

98 file=sys.stderr, 

99 ) 

100 

101 

102@click.command(cls=PipetaskCommand, epilog=epilog, short_help="Build pipeline definition.") 

103@click.pass_context 

104@ctrlMpExecOpts.show_option() 

105@ctrlMpExecOpts.pipeline_build_options() 

106@option_section(sectionText="") 

107@options_file_option() 

108@catch_and_exit 

109def build(ctx: click.Context, **kwargs: Any) -> None: 

110 """Build and optionally save pipeline definition. 

111 

112 This does not require input data to be specified. 

113 """ 

114 kwargs = _collectActions(ctx, **kwargs) 

115 show = ShowInfo(kwargs.pop("show", [])) 

116 script.build(**kwargs, show=show) 

117 _unhandledShow(show, "build") 

118 

119 

120@click.command(cls=PipetaskCommand, epilog=epilog) 

121@click.pass_context 

122@ctrlMpExecOpts.show_option() 

123@ctrlMpExecOpts.pipeline_build_options() 

124@ctrlMpExecOpts.qgraph_options() 

125@ctrlMpExecOpts.butler_options() 

126@option_section(sectionText="") 

127@options_file_option() 

128@catch_and_exit 

129def qgraph(ctx: click.Context, **kwargs: Any) -> None: 

130 """Build and optionally save quantum graph.""" 

131 kwargs = _collectActions(ctx, **kwargs) 

132 show = ShowInfo(kwargs.pop("show", [])) 

133 pipeline = script.build(**kwargs, show=show) 

134 if show.handled and not show.unhandled: 

135 print( 

136 "No quantum graph generated. The --show option was given and all options were processed.", 

137 file=sys.stderr, 

138 ) 

139 return 

140 script.qgraph(pipelineObj=pipeline, **kwargs, show=show) 

141 _unhandledShow(show, "qgraph") 

142 

143 

144@click.command(cls=PipetaskCommand, epilog=epilog) 

145@ctrlMpExecOpts.run_options() 

146@catch_and_exit 

147def run(ctx: click.Context, **kwargs: Any) -> None: 

148 """Build and execute pipeline and quantum graph.""" 

149 kwargs = _collectActions(ctx, **kwargs) 

150 show = ShowInfo(kwargs.pop("show", [])) 

151 pipeline = script.build(**kwargs, show=show) 

152 if show.handled and not show.unhandled: 

153 print( 

154 "No quantum graph generated or pipeline executed. " 

155 "The --show option was given and all options were processed.", 

156 file=sys.stderr, 

157 ) 

158 return 

159 qgraph = script.qgraph(pipelineObj=pipeline, **kwargs, show=show) 

160 _unhandledShow(show, "run") 

161 if show.handled: 

162 print( 

163 "No pipeline executed. The --show option was given and all options were processed.", 

164 file=sys.stderr, 

165 ) 

166 return 

167 script.run(qgraphObj=qgraph, **kwargs) 

168 

169 

170@click.command(cls=PipetaskCommand) 

171@ctrlMpExecOpts.butler_config_option() 

172@ctrlMpExecOpts.collection_argument() 

173@confirm_option() 

174@ctrlMpExecOpts.recursive_option( 

175 help="""If the parent CHAINED collection has child CHAINED collections, 

176 search the children until nested chains that start with the parent's name 

177 are removed.""" 

178) 

179def purge(confirm: bool, **kwargs: Any) -> None: 

180 """Remove a CHAINED collection and its contained collections. 

181 

182 COLLECTION is the name of the chained collection to purge. it must not be a 

183 child of any other CHAINED collections 

184 

185 Child collections must be members of exactly one collection. 

186 

187 The collections that will be removed will be printed, there will be an 

188 option to continue or abort (unless using --no-confirm). 

189 """ 

190 confirmable.confirm(partial(script.purge, **kwargs), confirm) 

191 

192 

193@click.command(cls=PipetaskCommand) 

194@ctrlMpExecOpts.butler_config_option() 

195@ctrlMpExecOpts.collection_argument() 

196@confirm_option() 

197def cleanup(confirm: bool, **kwargs: Any) -> None: 

198 """Remove non-members of CHAINED collections. 

199 

200 Removes collections that start with the same name as a CHAINED 

201 collection but are not members of that collection. 

202 """ 

203 confirmable.confirm(partial(script.cleanup, **kwargs), confirm)