"""Useful functions used to implement constraints and predicates."""fromtypingimportAny,Dict,Iterable,List,SequencefromclickimportArgument,Context,Option,Parameter
[docs]defparam_value_is_set(param:Parameter,value:Any)->bool:"""Define what it means for a parameter of a specific kind to be "set". All cases are obvious besides that of boolean options: - (common rule) if the value is ``None``, the parameter is unset; - a parameter that takes multiple values is set if at least one argument is provided; - a boolean **flag** is set only if True; - a boolean option is set if not None, even if it's False. """ifvalueisNone:returnFalse# checking for param.is_flag is redundant but necessary to work around# Click 8.0.1 issue: https://github.com/pallets/click/issues/1925elifisinstance(param,Option)andparam.is_flagandparam.is_bool_flag:returnbool(value)elifparam.nargs!=1orparam.multiple:returnlen(value)>0returnTrue
[docs]defget_param_name(param:Parameter)->str:"""Return the name of a parameter casted to ``str``. Use this function to avoid typing errors in places where you expect a parameter having a name. """ifparam.nameisNone:raiseTypeError('`param.name` is required to be a string in this context.\n''Hint: `param.name` is None only when `parameter.expose_value` is False, ''so you are probably using this option incorrectly.')returnparam.name
[docs]defget_params_whose_value_is_set(params:Iterable[Parameter],values:Dict[str,Any])->List[Parameter]:"""Filter ``params``, returning only the parameters that have a value. Boolean flags are considered "set" if their value is ``True``."""return[pforpinparamsifparam_value_is_set(p,values[get_param_name(p)])]
[docs]defjoin_with_and(strings:Sequence[str],sep:str=', ')->str:ifnotstrings:return''iflen(strings)==1:returnstrings[0]returnsep.join(strings[:-1])+' and '+strings[-1]
[docs]defparam_value_by_name(ctx:Context,name:str)->Any:try:returnctx.params[name]exceptKeyError:raiseKeyError(f'"{name}" is not the name of a CLI parameter')