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

56 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:13 +0000

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='Flag --{} must have a value other than None.'.format(flag_name), 

233 flag_values=flag_values) 

234 

235 

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

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

238 

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

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

241 

242 if __name__ == '__main__': 

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

244 app.run() 

245 

246 Args: 

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

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

249 are defined. 

250 Raises: 

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

252 """ 

253 for flag_name in flag_names: 

254 mark_flag_as_required(flag_name, flag_values) 

255 

256 

257def mark_flags_as_mutual_exclusive(flag_names, required=False, 

258 flag_values=_flagvalues.FLAGS): 

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

260 

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

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

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

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

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

266 

267 Args: 

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

269 Positional-only parameter. 

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

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

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

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

274 are defined. 

275 

276 Raises: 

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

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

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

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

281 """ 

282 flag_names, flag_values = _flagvalues.resolve_flag_refs( 

283 flag_names, flag_values) 

284 for flag_name in flag_names: 

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

286 warnings.warn( 

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

288 'with mark_flags_as_mutual_exclusive, which checks whether the ' 

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

290 stacklevel=2) 

291 

292 def validate_mutual_exclusion(flags_dict): 

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

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

295 return True 

296 raise _exceptions.ValidationError( 

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

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

299 

300 register_multi_flags_validator( 

301 flag_names, validate_mutual_exclusion, flag_values=flag_values) 

302 

303 

304def mark_bool_flags_as_mutual_exclusive(flag_names, required=False, 

305 flag_values=_flagvalues.FLAGS): 

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

307 

308 Args: 

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

310 Positional-only parameter. 

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

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

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

314 are defined. 

315 

316 Raises: 

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

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

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

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

321 """ 

322 flag_names, flag_values = _flagvalues.resolve_flag_refs( 

323 flag_names, flag_values) 

324 for flag_name in flag_names: 

325 if not flag_values[flag_name].boolean: 

326 raise _exceptions.ValidationError( 

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

328 'mark_bool_flags_as_mutual_exclusive.'.format(flag_name)) 

329 

330 def validate_boolean_mutual_exclusion(flags_dict): 

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

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

333 return True 

334 raise _exceptions.ValidationError( 

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

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

337 

338 register_multi_flags_validator( 

339 flag_names, validate_boolean_mutual_exclusion, flag_values=flag_values) 

340 

341 

342def _add_validator(fv, validator_instance): 

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

344 

345 Args: 

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

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

348 Raises: 

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

350 """ 

351 for flag_name in validator_instance.get_flags_names(): 

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