Hide keyboard shortcuts

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 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 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 click 

23import os 

24from unittest.mock import MagicMock 

25 

26from ..core.utils import iterable 

27 

28 

29# CLI_BUTLER_MOCK_ENV is set by some tests as an environment variable, it 

30# indicates to the cli_handle_exception function that instead of executing the 

31# command implementation function it should use the Mocker class for unit test 

32# verification. 

33mockEnvVarKey = "CLI_BUTLER_MOCK_ENV" 

34mockEnvVar = {mockEnvVarKey: "1"} 

35 

36 

37class Mocker: 

38 

39 mock = MagicMock() 

40 

41 def __init__(self, *args, **kwargs): 

42 """Mocker is a helper class for unit tests. It can be imported and 

43 called and later imported again and call can be verified. 

44 

45 For convenience, constructor arguments are forwarded to the call 

46 function. 

47 """ 

48 self.__call__(*args, **kwargs) 

49 

50 def __call__(self, *args, **kwargs): 

51 """Creates a MagicMock and stores it in a static variable that can 

52 later be verified. 

53 """ 

54 Mocker.mock(*args, **kwargs) 

55 

56 

57def split_commas(context, param, values): 

58 """Process a tuple of values, where each value may contain comma-separated 

59 values, and return a single list of all the passed-in values. 

60 

61 This function can be passed to the 'callback' argument of a click.option to 

62 allow it to process comma-separated values (e.g. "--my-opt a,b,c"). 

63 

64 Parameters 

65 ---------- 

66 context : `click.Context` or `None` 

67 The current execution context. Unused, but Click always passes it to 

68 callbacks. 

69 param : `click.core.Option` or `None` 

70 The parameter being handled. Unused, but Click always passes it to 

71 callbacks. 

72 values : [`str`] 

73 All the values passed for this option. Strings may contain commas, 

74 which will be treated as delimiters for separate values. 

75 

76 Returns 

77 ------- 

78 list of string 

79 The passed in values separated by commas and combined into a single 

80 list. 

81 """ 

82 valueList = [] 

83 for value in iterable(values): 

84 valueList.extend(value.split(",")) 

85 return valueList 

86 

87 

88def split_kv(context, param, values, separator="="): 

89 """Process a tuple of values that are key-value pairs separated by a given 

90 separator. Multiple pairs may be comma separated. Return a dictionary of 

91 all the passed-in values. 

92 

93 This function can be passed to the 'callback' argument of a click.option to 

94 allow it to process comma-separated values (e.g. "--my-opt a=1,b=2"). 

95 

96 Parameters 

97 ---------- 

98 context : `click.Context` or `None` 

99 The current execution context. Unused, but Click always passes it to 

100 callbacks. 

101 param : `click.core.Option` or `None` 

102 The parameter being handled. Unused, but Click always passes it to 

103 callbacks. 

104 values : [`str`] 

105 All the values passed for this option. Strings may contain commas, 

106 which will be treated as delimiters for separate values. 

107 separator : str, optional 

108 The character that separates key-value pairs. May not be a comma or an 

109 empty space (for space separators use Click's default implementation 

110 for tuples; `type=(str, str)`). By default "=". 

111 

112 Returns 

113 ------- 

114 `dict` : [`str`, `str`] 

115 The passed-in values in dict form. 

116 

117 Raises 

118 ------ 

119 `click.ClickException` 

120 Raised if the separator is not found in an entry, or if duplicate keys 

121 are encountered. 

122 """ 

123 if "," == separator or " " == separator: 

124 raise RuntimeError(f"'{separator}' is not a supported separator for key-value pairs.") 

125 vals = split_commas(context, param, values) 

126 ret = {} 

127 for val in vals: 

128 try: 

129 k, v = val.split(separator) 

130 except ValueError: 

131 raise click.ClickException(f"Missing or invalid key-value separator in value '{val}'") 

132 if k in ret: 

133 raise click.ClickException(f"Duplicate entries for '{k}' in '{values}'") 

134 ret[k] = v 

135 return ret 

136 

137 

138def to_upper(context, param, value): 

139 """Convert a value to upper case. 

140 

141 Parameters 

142 ---------- 

143 context : click.Context 

144 

145 values : string 

146 The value to be converted. 

147 

148 Returns 

149 ------- 

150 string 

151 A copy of the passed-in value, converted to upper case. 

152 """ 

153 return value.upper() 

154 

155 

156def cli_handle_exception(func, *args, **kwargs): 

157 """Wrap a function call in an exception handler that raises a 

158 ClickException if there is an Exception. 

159 

160 Also provides support for unit testing by testing for an environment 

161 variable, and if it is present prints the function name, args, and kwargs 

162 to stdout so they can be read and verified by the unit test code. 

163 

164 Parameters 

165 ---------- 

166 func : function 

167 A function to be called and exceptions handled. Will pass args & kwargs 

168 to the function. 

169 

170 Returns 

171 ------- 

172 The result of calling func. 

173 

174 Raises 

175 ------ 

176 click.ClickException 

177 An exception to be handled by the Click CLI tool. 

178 """ 

179 if mockEnvVarKey in os.environ: 

180 Mocker(*args, **kwargs) 

181 return 

182 try: 

183 return func(*args, **kwargs) 

184 except Exception as err: 

185 raise click.ClickException(err)