From b239bb7e87aa07e37d9166f1b21797f3f9a37983 Mon Sep 17 00:00:00 2001 From: joshuaswanson Date: Wed, 25 Mar 2026 20:59:58 +0100 Subject: [PATCH 1/2] gh-126676: Expand argparse docs for type=bool with warning and alternatives --- Doc/library/argparse.rst | 55 ++++++++++++++++++- ...-03-25-00-00-00.gh-issue-126676.052336.rst | 4 ++ 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 5a463ee9821d61..254d6b2ea794da 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1116,9 +1116,58 @@ User defined functions can be used as well: >>> parser.parse_args(['"The Tale of Two Cities"']) Namespace(short_title='"the-tale-of-two-citi') -The :func:`bool` function is not recommended as a type converter. All it does -is convert empty strings to ``False`` and non-empty strings to ``True``. -This is usually not what is desired. +.. warning:: + + The :func:`bool` function is not recommended as a type converter. All it + does is convert empty strings to ``False`` and non-empty strings to + ``True``. This is usually not what is desired:: + + >>> parser = argparse.ArgumentParser() + >>> _ = parser.add_argument('--verbose', type=bool) + >>> parser.parse_args(['--verbose', 'False']) + Namespace(verbose=True) + + ``'False'`` is a non-empty string, so :func:`bool` converts it to + ``True``. + + To handle boolean flags, use one of the following patterns instead: + + * For ``--flag``/``--no-flag`` style options, use + :class:`BooleanOptionalAction`:: + + >>> parser = argparse.ArgumentParser() + >>> _ = parser.add_argument('--verbose', action=argparse.BooleanOptionalAction) + >>> parser.parse_args(['--verbose']) + Namespace(verbose=True) + >>> parser.parse_args(['--no-verbose']) + Namespace(verbose=False) + + * For a flag that sets a ``True`` or ``False`` value, use + ``action='store_true'`` or ``action='store_false'``:: + + >>> parser = argparse.ArgumentParser() + >>> _ = parser.add_argument('--verbose', action='store_true') + >>> parser.parse_args(['--verbose']) + Namespace(verbose=True) + >>> parser.parse_args([]) + Namespace(verbose=False) + + * For a positional or option that accepts the strings ``'true'`` or + ``'false'``, define a converter function:: + + >>> def str_to_bool(value): + ... if value.casefold() in ('true', '1', 'yes'): + ... return True + ... elif value.casefold() in ('false', '0', 'no'): + ... return False + ... raise argparse.ArgumentTypeError(f'{value!r} is not a boolean value') + ... + >>> parser = argparse.ArgumentParser() + >>> _ = parser.add_argument('--verbose', type=str_to_bool) + >>> parser.parse_args(['--verbose', 'yes']) + Namespace(verbose=True) + >>> parser.parse_args(['--verbose', 'false']) + Namespace(verbose=False) In general, the ``type`` keyword is a convenience that should only be used for simple conversions that can only raise one of the three supported exceptions. diff --git a/Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst b/Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst new file mode 100644 index 00000000000000..f6c8b83d1c1582 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst @@ -0,0 +1,4 @@ +Expand :mod:`argparse` documentation for ``type=bool`` with a warning +admonition, a demonstration of the surprising behavior, and recommended +alternatives (``BooleanOptionalAction``, ``store_true``/``store_false``, +and a custom converter function). From 4defa1bb34a127abd587996731d93bf55ff861a0 Mon Sep 17 00:00:00 2001 From: joshuaswanson Date: Fri, 3 Apr 2026 19:44:37 +0200 Subject: [PATCH 2/2] Address review: remove warning admonition, condense alternatives to one line --- Doc/library/argparse.rst | 59 +++---------------- ...-03-25-00-00-00.gh-issue-126676.052336.rst | 6 +- 2 files changed, 11 insertions(+), 54 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 254d6b2ea794da..8ba11b7d12d552 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1116,58 +1116,17 @@ User defined functions can be used as well: >>> parser.parse_args(['"The Tale of Two Cities"']) Namespace(short_title='"the-tale-of-two-citi') -.. warning:: +The :func:`bool` function is not recommended as a type converter. All it does +is convert empty strings to ``False`` and non-empty strings to ``True``. +This is usually not what is desired:: - The :func:`bool` function is not recommended as a type converter. All it - does is convert empty strings to ``False`` and non-empty strings to - ``True``. This is usually not what is desired:: + >>> parser = argparse.ArgumentParser() + >>> _ = parser.add_argument('--verbose', type=bool) + >>> parser.parse_args(['--verbose', 'False']) + Namespace(verbose=True) - >>> parser = argparse.ArgumentParser() - >>> _ = parser.add_argument('--verbose', type=bool) - >>> parser.parse_args(['--verbose', 'False']) - Namespace(verbose=True) - - ``'False'`` is a non-empty string, so :func:`bool` converts it to - ``True``. - - To handle boolean flags, use one of the following patterns instead: - - * For ``--flag``/``--no-flag`` style options, use - :class:`BooleanOptionalAction`:: - - >>> parser = argparse.ArgumentParser() - >>> _ = parser.add_argument('--verbose', action=argparse.BooleanOptionalAction) - >>> parser.parse_args(['--verbose']) - Namespace(verbose=True) - >>> parser.parse_args(['--no-verbose']) - Namespace(verbose=False) - - * For a flag that sets a ``True`` or ``False`` value, use - ``action='store_true'`` or ``action='store_false'``:: - - >>> parser = argparse.ArgumentParser() - >>> _ = parser.add_argument('--verbose', action='store_true') - >>> parser.parse_args(['--verbose']) - Namespace(verbose=True) - >>> parser.parse_args([]) - Namespace(verbose=False) - - * For a positional or option that accepts the strings ``'true'`` or - ``'false'``, define a converter function:: - - >>> def str_to_bool(value): - ... if value.casefold() in ('true', '1', 'yes'): - ... return True - ... elif value.casefold() in ('false', '0', 'no'): - ... return False - ... raise argparse.ArgumentTypeError(f'{value!r} is not a boolean value') - ... - >>> parser = argparse.ArgumentParser() - >>> _ = parser.add_argument('--verbose', type=str_to_bool) - >>> parser.parse_args(['--verbose', 'yes']) - Namespace(verbose=True) - >>> parser.parse_args(['--verbose', 'false']) - Namespace(verbose=False) +See :class:`BooleanOptionalAction` or ``action='store_true'`` for common +alternatives. In general, the ``type`` keyword is a convenience that should only be used for simple conversions that can only raise one of the three supported exceptions. diff --git a/Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst b/Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst index f6c8b83d1c1582..d2e275fdf08385 100644 --- a/Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst +++ b/Misc/NEWS.d/next/Documentation/2026-03-25-00-00-00.gh-issue-126676.052336.rst @@ -1,4 +1,2 @@ -Expand :mod:`argparse` documentation for ``type=bool`` with a warning -admonition, a demonstration of the surprising behavior, and recommended -alternatives (``BooleanOptionalAction``, ``store_true``/``store_false``, -and a custom converter function). +Expand :mod:`argparse` documentation for ``type=bool`` with a demonstration +of the surprising behavior and pointers to common alternatives.