Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/absl_py-2.1.0-py3.8.egg/absl/flags/_validators.py: 25%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

56 statements  

1# Copyright 2017 The Abseil Authors. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15"""Module to enforce different constraints on flags. 

16 

17Flags validators can be registered using following functions / decorators:: 

18 

19 flags.register_validator 

20 @flags.validator 

21 flags.register_multi_flags_validator 

22 @flags.multi_flags_validator 

23 

24Three convenience functions are also provided for common flag constraints:: 

25 

26 flags.mark_flag_as_required 

27 flags.mark_flags_as_required 

28 flags.mark_flags_as_mutual_exclusive 

29 flags.mark_bool_flags_as_mutual_exclusive 

30 

31See their docstring in this module for a usage manual. 

32 

33Do NOT import this module directly. Import the flags package and use the 

34aliases defined at the package level instead. 

35""" 

36 

37import warnings 

38 

39from absl.flags import _exceptions 

40from absl.flags import _flagvalues 

41from absl.flags import _validators_classes 

42 

43 

44def register_validator(flag_name, 

45 checker, 

46 message='Flag validation failed', 

47 flag_values=_flagvalues.FLAGS): 

48 """Adds a constraint, which will be enforced during program execution. 

49 

50 The constraint is validated when flags are initially parsed, and after each 

51 change of the corresponding flag's value. 

52 

53 Args: 

54 flag_name: str | FlagHolder, name or holder of the flag to be checked. 

55 Positional-only parameter. 

56 checker: callable, a function to validate the flag. 

57 

58 * input - A single positional argument: The value of the corresponding 

59 flag (string, boolean, etc. This value will be passed to checker 

60 by the library). 

61 * output - bool, True if validator constraint is satisfied. 

62 If constraint is not satisfied, it should either ``return False`` or 

63 ``raise flags.ValidationError(desired_error_message)``. 

64 

65 message: str, error text to be shown to the user if checker returns False. 

66 If checker raises flags.ValidationError, message from the raised 

67 error will be shown. 

68 flag_values: flags.FlagValues, optional FlagValues instance to validate 

69 against. 

70 

71 Raises: 

72 AttributeError: Raised when flag_name is not registered as a valid flag 

73 name. 

74 ValueError: Raised when flag_values is non-default and does not match the 

75 FlagValues of the provided FlagHolder instance. 

76 """ 

77 flag_name, flag_values = _flagvalues.resolve_flag_ref(flag_name, flag_values) 

78 v = _validators_classes.SingleFlagValidator(flag_name, checker, message) 

79 _add_validator(flag_values, v) 

80 

81 

82def validator(flag_name, message='Flag validation failed', 

83 flag_values=_flagvalues.FLAGS): 

84 """A function decorator for defining a flag validator. 

85 

86 Registers the decorated function as a validator for flag_name, e.g.:: 

87 

88 @flags.validator('foo') 

89 def _CheckFoo(foo): 

90 ... 

91 

92 See :func:`register_validator` for the specification of checker function. 

93 

94 Args: 

95 flag_name: str | FlagHolder, name or holder of the flag to be checked. 

96 Positional-only parameter. 

97 message: str, error text to be shown to the user if checker returns False. 

98 If checker raises flags.ValidationError, message from the raised 

99 error will be shown. 

100 flag_values: flags.FlagValues, optional FlagValues instance to validate 

101 against. 

102 Returns: 

103 A function decorator that registers its function argument as a validator. 

104 Raises: 

105 AttributeError: Raised when flag_name is not registered as a valid flag 

106 name. 

107 """ 

108 

109 def decorate(function): 

110 register_validator(flag_name, function, 

111 message=message, 

112 flag_values=flag_values) 

113 return function 

114 return decorate 

115 

116 

117def register_multi_flags_validator(flag_names, 

118 multi_flags_checker, 

119 message='Flags validation failed', 

120 flag_values=_flagvalues.FLAGS): 

121 """Adds a constraint to multiple flags. 

122 

123 The constraint is validated when flags are initially parsed, and after each 

124 change of the corresponding flag's value. 

125 

126 Args: 

127 flag_names: [str | FlagHolder], a list of the flag names or holders to be 

128 checked. Positional-only parameter. 

129 multi_flags_checker: callable, a function to validate the flag. 

130 

131 * input - dict, with keys() being flag_names, and value for each key 

132 being the value of the corresponding flag (string, boolean, etc). 

133 * output - bool, True if validator constraint is satisfied. 

134 If constraint is not satisfied, it should either return False or 

135 raise flags.ValidationError. 

136 

137 message: str, error text to be shown to the user if checker returns False. 

138 If checker raises flags.ValidationError, message from the raised 

139 error will be shown. 

140 flag_values: flags.FlagValues, optional FlagValues instance to validate 

141 against. 

142 

143 Raises: 

144 AttributeError: Raised when a flag is not registered as a valid flag name. 

145 ValueError: Raised when multiple FlagValues are used in the same 

146 invocation. This can occur when FlagHolders have different `_flagvalues` 

147 or when str-type flag_names entries are present and the `flag_values` 

148 argument does not match that of provided FlagHolder(s). 

149 """ 

150 flag_names, flag_values = _flagvalues.resolve_flag_refs( 

151 flag_names, flag_values) 

152 v = _validators_classes.MultiFlagsValidator( 

153 flag_names, multi_flags_checker, message) 

154 _add_validator(flag_values, v) 

155 

156 

157def multi_flags_validator(flag_names, 

158 message='Flag validation failed', 

159 flag_values=_flagvalues.FLAGS): 

160 """A function decorator for defining a multi-flag validator. 

161 

162 Registers the decorated function as a validator for flag_names, e.g.:: 

163 

164 @flags.multi_flags_validator(['foo', 'bar']) 

165 def _CheckFooBar(flags_dict): 

166 ... 

167 

168 See :func:`register_multi_flags_validator` for the specification of checker 

169 function. 

170 

171 Args: 

172 flag_names: [str | FlagHolder], a list of the flag names or holders to be 

173 checked. Positional-only parameter. 

174 message: str, error text to be shown to the user if checker returns False. 

175 If checker raises flags.ValidationError, message from the raised 

176 error will be shown. 

177 flag_values: flags.FlagValues, optional FlagValues instance to validate 

178 against. 

179 

180 Returns: 

181 A function decorator that registers its function argument as a validator. 

182 

183 Raises: 

184 AttributeError: Raised when a flag is not registered as a valid flag name. 

185 """ 

186 

187 def decorate(function): 

188 register_multi_flags_validator(flag_names, 

189 function, 

190 message=message, 

191 flag_values=flag_values) 

192 return function 

193 

194 return decorate 

195 

196 

197def mark_flag_as_required(flag_name, flag_values=_flagvalues.FLAGS): 

198 """Ensures that flag is not None during program execution. 

199 

200 Registers a flag validator, which will follow usual validator rules. 

201 Important note: validator will pass for any non-``None`` value, such as 

202 ``False``, ``0`` (zero), ``''`` (empty string) and so on. 

203 

204 If your module might be imported by others, and you only wish to make the flag 

205 required when the module is directly executed, call this method like this:: 

206 

207 if __name__ == '__main__': 

208 flags.mark_flag_as_required('your_flag_name') 

209 app.run() 

210 

211 Args: 

212 flag_name: str | FlagHolder, name or holder of the flag. 

213 Positional-only parameter. 

214 flag_values: flags.FlagValues, optional :class:`~absl.flags.FlagValues` 

215 instance where the flag is defined. 

216 Raises: 

217 AttributeError: Raised when flag_name is not registered as a valid flag 

218 name. 

219 ValueError: Raised when flag_values is non-default and does not match the 

220 FlagValues of the provided FlagHolder instance. 

221 """ 

222 flag_name, flag_values = _flagvalues.resolve_flag_ref(flag_name, flag_values) 

223 if flag_values[flag_name].default is not None: 

224 warnings.warn( 

225 'Flag --%s has a non-None default value; therefore, ' 

226 'mark_flag_as_required will pass even if flag is not specified in the ' 

227 'command line!' % flag_name, 

228 stacklevel=2) 

229 register_validator( 

230 flag_name, 

231 lambda value: value is not None, 

232 message=f'Flag --{flag_name} must have a value other than None.', 

233 flag_values=flag_values, 

234 ) 

235 

236 

237def mark_flags_as_required(flag_names, flag_values=_flagvalues.FLAGS): 

238 """Ensures that flags are not None during program execution. 

239 

240 If your module might be imported by others, and you only wish to make the flag 

241 required when the module is directly executed, call this method like this:: 

242 

243 if __name__ == '__main__': 

244 flags.mark_flags_as_required(['flag1', 'flag2', 'flag3']) 

245 app.run() 

246 

247 Args: 

248 flag_names: Sequence[str | FlagHolder], names or holders of the flags. 

249 flag_values: flags.FlagValues, optional FlagValues instance where the flags 

250 are defined. 

251 Raises: 

252 AttributeError: If any of flag name has not already been defined as a flag. 

253 """ 

254 for flag_name in flag_names: 

255 mark_flag_as_required(flag_name, flag_values) 

256 

257 

258def mark_flags_as_mutual_exclusive(flag_names, required=False, 

259 flag_values=_flagvalues.FLAGS): 

260 """Ensures that only one flag among flag_names is not None. 

261 

262 Important note: This validator checks if flag values are ``None``, and it does 

263 not distinguish between default and explicit values. Therefore, this validator 

264 does not make sense when applied to flags with default values other than None, 

265 including other false values (e.g. ``False``, ``0``, ``''``, ``[]``). That 

266 includes multi flags with a default value of ``[]`` instead of None. 

267 

268 Args: 

269 flag_names: [str | FlagHolder], names or holders of flags. 

270 Positional-only parameter. 

271 required: bool. If true, exactly one of the flags must have a value other 

272 than None. Otherwise, at most one of the flags can have a value other 

273 than None, and it is valid for all of the flags to be None. 

274 flag_values: flags.FlagValues, optional FlagValues instance where the flags 

275 are defined. 

276 

277 Raises: 

278 ValueError: Raised when multiple FlagValues are used in the same 

279 invocation. This can occur when FlagHolders have different `_flagvalues` 

280 or when str-type flag_names entries are present and the `flag_values` 

281 argument does not match that of provided FlagHolder(s). 

282 """ 

283 flag_names, flag_values = _flagvalues.resolve_flag_refs( 

284 flag_names, flag_values) 

285 for flag_name in flag_names: 

286 if flag_values[flag_name].default is not None: 

287 warnings.warn( 

288 'Flag --{} has a non-None default value. That does not make sense ' 

289 'with mark_flags_as_mutual_exclusive, which checks whether the ' 

290 'listed flags have a value other than None.'.format(flag_name), 

291 stacklevel=2) 

292 

293 def validate_mutual_exclusion(flags_dict): 

294 flag_count = sum(1 for val in flags_dict.values() if val is not None) 

295 if flag_count == 1 or (not required and flag_count == 0): 

296 return True 

297 raise _exceptions.ValidationError( 

298 '{} one of ({}) must have a value other than None.'.format( 

299 'Exactly' if required else 'At most', ', '.join(flag_names))) 

300 

301 register_multi_flags_validator( 

302 flag_names, validate_mutual_exclusion, flag_values=flag_values) 

303 

304 

305def mark_bool_flags_as_mutual_exclusive(flag_names, required=False, 

306 flag_values=_flagvalues.FLAGS): 

307 """Ensures that only one flag among flag_names is True. 

308 

309 Args: 

310 flag_names: [str | FlagHolder], names or holders of flags. 

311 Positional-only parameter. 

312 required: bool. If true, exactly one flag must be True. Otherwise, at most 

313 one flag can be True, and it is valid for all flags to be False. 

314 flag_values: flags.FlagValues, optional FlagValues instance where the flags 

315 are defined. 

316 

317 Raises: 

318 ValueError: Raised when multiple FlagValues are used in the same 

319 invocation. This can occur when FlagHolders have different `_flagvalues` 

320 or when str-type flag_names entries are present and the `flag_values` 

321 argument does not match that of provided FlagHolder(s). 

322 """ 

323 flag_names, flag_values = _flagvalues.resolve_flag_refs( 

324 flag_names, flag_values) 

325 for flag_name in flag_names: 

326 if not flag_values[flag_name].boolean: 

327 raise _exceptions.ValidationError( 

328 'Flag --{} is not Boolean, which is required for flags used in ' 

329 'mark_bool_flags_as_mutual_exclusive.'.format(flag_name)) 

330 

331 def validate_boolean_mutual_exclusion(flags_dict): 

332 flag_count = sum(bool(val) for val in flags_dict.values()) 

333 if flag_count == 1 or (not required and flag_count == 0): 

334 return True 

335 raise _exceptions.ValidationError( 

336 '{} one of ({}) must be True.'.format( 

337 'Exactly' if required else 'At most', ', '.join(flag_names))) 

338 

339 register_multi_flags_validator( 

340 flag_names, validate_boolean_mutual_exclusion, flag_values=flag_values) 

341 

342 

343def _add_validator(fv, validator_instance): 

344 """Register new flags validator to be checked. 

345 

346 Args: 

347 fv: flags.FlagValues, the FlagValues instance to add the validator. 

348 validator_instance: validators.Validator, the validator to add. 

349 Raises: 

350 KeyError: Raised when validators work with a non-existing flag. 

351 """ 

352 for flag_name in validator_instance.get_flags_names(): 

353 fv[flag_name].validators.append(validator_instance)