Passing booleans to python argparse as str
Needed argparse to accept yes/no decisions, should have been used inside a dockerfile that doesn’t have if/else logic, and all solutions except getting a parameter that accepts string like true/false seemed ugly.
The standard linux --do-thing
and --no-do-thing
were also impossible to do within Docker, if I want to use an env. variable etc., unless I literally set them to --do-thing
which is a mess for many reasons.
I had 40 tabs open because apparently this is not a solved problem, and all ideas I had felt ugly.
How do I convert strings to bools in a good way? (bool
alone is not an option because bool('False')
etc.)
Basic if value=="true"
would work, but maybe let’s support other things as a bonus because why not.
My first thought was to see what YAML does, but then I found the deprecated in 3.12 distutils.util.strtobool
: 9. API Reference — Python 3.9.17 documentation
It converts y,yes,t,true,on,1 / n,no,f,false,off,0 into boolean True
/False
.
The code, the only reason it’s a separate function (and not a lambda inside the type=
parameter) was because I wanted a custom ValueError and to add the warning for deprecation, as if Python would let me forget. An one-liner was absolutely possible here as well.
def _str_to_bool(x: str):
"""Converts value to a boolean.
Currently uses (the rules from) distutils.util.strtobool:
(https://docs.python.org/3.9/distutils/apiref.html#distutils.util.strtobool)
True values are y, yes, t, true, on and 1
False values are n, no, f, false, off and 0
ValueError otherwise.
! distutils.util.strtobool is deprecated in python 3.12
TODO solve it differently by then
Args:
value (str): value
"""
try:
res = bool(strtobool(str(x).strip()))
except ValueError as e:
logger.error(
f"Invalid str-to-bool value '{x}'. Valid values are: y,yes,t,true,on,1 / n,no,f,false,off,0."
)
raise e
return res
# inside argparse
parser.add_argument(
"--skip-cert-check",
help="Whether to skip a cert check (%(default)s)",
type=_str_to_bool,
default=SKIP_CERT_CHECK,
)
This allows:
- sane human-readable default values specified elsewhere
- use inside Dockerfiles and Rancher configmaps etc. where you just set it to a plaintext value
- no if/else bits for
--no-do-thing
flags
distutils
is deprecated in 3.12 though :(
YAML is known for it’s bool handling: Boolean Language-Independent Type for YAML™ Version 1.1.
Regexp:
y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF`
I don’t like it and think it creates more issues than it solves, e.g. the “Norway problem” (211020-1304 YAML Norway issues), but for CLI I think that’s okay enough.