From ed9787c275c84b9d6575259e98018b8847ec7559 Mon Sep 17 00:00:00 2001 From: David Steele Date: Sun, 6 Sep 2020 20:51:44 -0400 Subject: [PATCH 01/16] bpo12806: Add argparse FlexiHelpFormatter --- Doc/library/argparse.rst | 57 ++++++++++++- Lib/argparse.py | 82 ++++++++++++++++++- Lib/test/test_argparse.py | 67 +++++++++++++++ .../2020-09-07-00-00-51.bpo-12806.j1A_9o.rst | 3 + 4 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 8d0116d8c060b8..67c5a83c697811 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -295,11 +295,13 @@ classes: .. class:: RawDescriptionHelpFormatter RawTextHelpFormatter + FlexiHelpFormatter ArgumentDefaultsHelpFormatter MetavarTypeHelpFormatter -:class:`RawDescriptionHelpFormatter` and :class:`RawTextHelpFormatter` give -more control over how textual descriptions are displayed. +:class:`RawDescriptionHelpFormatter`, :class:`RawTextHelpFormatter`, and +:class:`FlexiHelpFormatter` give more control over how textual descriptions +are displayed. By default, :class:`ArgumentParser` objects line-wrap the description_ and epilog_ texts in command-line help messages:: @@ -354,6 +356,57 @@ including argument descriptions. However, multiple newlines are replaced with one. If you wish to preserve multiple blank lines, add spaces between the newlines. +:class:`FlexiHelpFormatter` wraps description and help text like the default +formatter, while preserving paragraphs and supporting bulleted lists. Bullet +list items are marked by the use of the "*", "-", "+", or ">" characters, or a +single non-whitespace character followed by a ".":: + + >>> parser = argparse.ArgumentParser( + ... prog='PROG', + ... formatter_class=argparse.FlexiHelpFormatter, + ... description=""" + ... The FlexiHelpFormatter will wrap text within paragraphs + ... when required to in order to make the text fit. + ... + ... Paragraphs are preserved. + ... + ... It also supports bulleted lists in a number of formats: + ... * stars + ... 1. numbers + ... - ... and so on + ... """) + >>> parser.add_argument( + ... "argument", + ... help=""" + ... Argument help text also supports flexible formatting, + ... with word wrap: + ... * See? + ... """) + >>> parser.print_help() + usage: PROG [-h] option + + The FlexiHelpFormatter will wrap text within paragraphs when required to in + order to make the text fit. + + Paragraphs are preserved. + + It also supports bulleted lists in a number of formats: + * stars + 1. numbers + - ... and so on + + positional arguments: + argument Argument help text also supports flexible formatting, with word + wrap: + * See? + + optional arguments: + -h, --help show this help message and exit + + +.. versionchanged:: 3.9 + :class:`FlexiHelpFormatter` class was added. + :class:`ArgumentDefaultsHelpFormatter` automatically adds information about default values to each of the argument help messages:: diff --git a/Lib/argparse.py b/Lib/argparse.py index d24fa72e573d4f..5839c3c27bf0bb 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -75,6 +75,7 @@ 'ArgumentDefaultsHelpFormatter', 'RawDescriptionHelpFormatter', 'RawTextHelpFormatter', + 'FlexiHelpFormatter', 'MetavarTypeHelpFormatter', 'Namespace', 'Action', @@ -513,7 +514,10 @@ def _format_action(self, action): help_lines = self._split_lines(help_text, help_width) parts.append('%*s%s\n' % (indent_first, '', help_lines[0])) for line in help_lines[1:]: - parts.append('%*s%s\n' % (help_position, '', line)) + if line.strip(): + parts.append('%*s%s\n' % (help_position, '', line)) + else: + parts.append("\n") # or add a newline if the description doesn't end with one elif not action_header.endswith('\n'): @@ -659,6 +663,82 @@ def _split_lines(self, text, width): return text.splitlines() +class FlexiHelpFormatter(HelpFormatter): + """Help message formatter which respects paragraphs and bulleted lists. + + Only the name of this class is considered a public API. All the methods + provided by the class are considered an implementation detail. + """ + + def _split_lines(self, text, width): + return self._para_reformat(text, width) + + def _fill_text(self, text, width, indent): + lines = self._para_reformat(text, width) + return "\n".join(lines) + + def _indents(self, line): + """Return line indent level and "sub_indent" for bullet list text.""" + + indent = len(_re.match(r"( *)", line).group(1)) + list_match = _re.match(r"( *)(([*-+>]+|\w+\)|\w+\.) +)", line) + if list_match: + sub_indent = indent + len(list_match.group(2)) + else: + sub_indent = indent + + return (indent, sub_indent) + + def _split_paragraphs(self, text): + """Split text in to paragraphs of like-indented lines.""" + + import textwrap + + text = textwrap.dedent(text).strip() + text = _re.sub("\n\n[\n]+", "\n\n", text) + + last_sub_indent = None + paragraphs = list() + for line in text.splitlines(): + (indent, sub_indent) = self._indents(line) + is_text = len(line.strip()) > 0 + + if is_text and indent == sub_indent == last_sub_indent: + paragraphs[-1] += " " + line + else: + paragraphs.append(line) + + if is_text: + last_sub_indent = sub_indent + else: + last_sub_indent = None + + return paragraphs + + def _para_reformat(self, text, width): + """Reformat text, by paragraph.""" + + import textwrap + + lines = list() + for paragraph in self._split_paragraphs(text): + + (indent, sub_indent) = self._indents(paragraph) + + paragraph = self._whitespace_matcher.sub(" ", paragraph).strip() + new_lines = textwrap.wrap( + text=paragraph, + width=width, + initial_indent=" " * indent, + subsequent_indent=" " * sub_indent, + ) + + # Blank lines get eaten by textwrap, put it back + lines.extend(new_lines or [""]) + + return lines + + class ArgumentDefaultsHelpFormatter(HelpFormatter): """Help message formatter which adds default values to argument help. diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 488a3a4ed20fac..ea8b7a93223385 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5272,6 +5272,73 @@ class TestHelpRawDescription(HelpTestCase): version = '' +class TestHelpFlexi(HelpTestCase): + """Test the FlexiHelpFormatter""" + + parser_signature = Sig( + prog='PROG', formatter_class=argparse.FlexiHelpFormatter, + description='This text should be wrapped as appropriate to keep\n' + 'things nice and very, very tidy.\n' + '\n' + 'Paragraphs should be preserved.\n' + ' * bullet list items\n' + ' should wrap to an appropriate place,\n' + ' should such wrapping be required.\n' + ' * short bullet\n' + ) + + argument_signatures = [ + Sig('--foo', help=' foo help should also\n' + 'appear as given here\n' + '\n' + 'along with a second paragraph, if called for\n' + ' * bullet'), + Sig('spam', help='spam help'), + ] + argument_group_signatures = [ + (Sig('title', description='short help text\n' + '\n' + 'Longer help text, containing useful\n' + 'contextual information for the var in\n' + 'question\n' + '* and a bullet\n'), + [Sig('--bar', help='bar help')]), + ] + usage = '''\ + usage: PROG [-h] [--foo FOO] [--bar BAR] spam + ''' + help = usage + '''\ + + This text should be wrapped as appropriate to keep things nice and very, very + tidy. + + Paragraphs should be preserved. + * bullet list items should wrap to an appropriate place, should such + wrapping be required. + * short bullet + + positional arguments: + spam spam help + + optional arguments: + -h, --help show this help message and exit + --foo FOO foo help should also appear as given here + + along with a second paragraph, if called for + * bullet + + title: + short help text + + Longer help text, containing useful contextual information for the var in + question + * and a bullet + + --bar BAR bar help + ''' + version = '' + + class TestHelpArgumentDefaults(HelpTestCase): """Test the ArgumentDefaultsHelpFormatter""" diff --git a/Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst b/Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst new file mode 100644 index 00000000000000..e74b4a05e4cc4f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst @@ -0,0 +1,3 @@ +The :mod:`argparse` module has a new :class:`argparse.FlexiHelpFormatter` +class that wraps help and description text while preserving paragraphs and +supporting bulleted lists. From 18b8311a7427efd958ea373a05af2f9e4fad3ba0 Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 23 Oct 2020 10:25:38 -0400 Subject: [PATCH 02/16] Update FlexiFormatter release to v3.10 --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 67c5a83c697811..34f7b1fcaa170a 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -404,7 +404,7 @@ single non-whitespace character followed by a ".":: -h, --help show this help message and exit -.. versionchanged:: 3.9 +.. versionadded:: 3.10 :class:`FlexiHelpFormatter` class was added. :class:`ArgumentDefaultsHelpFormatter` automatically adds information about From f692c5783cd6b9104cbb7c540cd7c354f7ac1dfa Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 5 Feb 2021 10:29:37 -0500 Subject: [PATCH 03/16] FlexiHelpFormatter: Recognize "-" bullets --- Lib/argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 5839c3c27bf0bb..82c98d4afe33aa 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -681,7 +681,7 @@ def _indents(self, line): """Return line indent level and "sub_indent" for bullet list text.""" indent = len(_re.match(r"( *)", line).group(1)) - list_match = _re.match(r"( *)(([*-+>]+|\w+\)|\w+\.) +)", line) + list_match = _re.match(r"( *)(([*\-+>]+|\w+\)|\w+\.) +)", line) if list_match: sub_indent = indent + len(list_match.group(2)) else: From 757311dea3babec9614d6cbd15b4bed5586bac1a Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 9 Apr 2021 12:39:38 -0400 Subject: [PATCH 04/16] Fix test --- Lib/test/test_argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index ea8b7a93223385..ebdaba79ad39ba 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5320,7 +5320,7 @@ class TestHelpFlexi(HelpTestCase): positional arguments: spam spam help - optional arguments: + options: -h, --help show this help message and exit --foo FOO foo help should also appear as given here From 6282547ea8a8c227db192607668b5a020208ded8 Mon Sep 17 00:00:00 2001 From: David Steele <565205+davesteele@users.noreply.github.com> Date: Fri, 9 Jul 2021 19:55:18 -0400 Subject: [PATCH 05/16] Set FlexiHelpFormatter release to 3.11 Rebase to force CI retest. The "addres sanitizer" test is failing with a timeout, on test_multiprocessing_fork.WithProcessesTestQueue(). It is not likely that this branch contributed to that failure. https://github.com/python/cpython/pull/22129/checks?check_run_id=3033564406 --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 34f7b1fcaa170a..53da6d6b545bf3 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -404,7 +404,7 @@ single non-whitespace character followed by a ".":: -h, --help show this help message and exit -.. versionadded:: 3.10 +.. versionadded:: 3.11 :class:`FlexiHelpFormatter` class was added. :class:`ArgumentDefaultsHelpFormatter` automatically adds information about From a21117a153a66ab811f8e32252419284e68aea96 Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 1 Mar 2024 20:35:40 -0500 Subject: [PATCH 06/16] Update FlexiHelpFormatter release to 3.13 --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 53da6d6b545bf3..77ca41d1215fce 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -404,7 +404,7 @@ single non-whitespace character followed by a ".":: -h, --help show this help message and exit -.. versionadded:: 3.11 +.. versionadded:: 3.13 :class:`FlexiHelpFormatter` class was added. :class:`ArgumentDefaultsHelpFormatter` automatically adds information about From 8e207548d4fcc41e7e704a92ad3a9b11aca4e55e Mon Sep 17 00:00:00 2001 From: David Steele <565205+davesteele@users.noreply.github.com> Date: Sun, 14 Dec 2025 21:01:41 -0500 Subject: [PATCH 07/16] Update Doc/library/argparse.rst Co-authored-by: Savannah Ostrowski --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 63aad6ef923082..37b13d768f9226 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -411,7 +411,7 @@ single non-whitespace character followed by a ".":: -h, --help show this help message and exit -.. versionadded:: 3.13 +.. versionadded:: 3.15 :class:`FlexiHelpFormatter` class was added. :class:`ArgumentDefaultsHelpFormatter` automatically adds information about From 2a53ad49b369b87f3219d1b2ffe4b4930fb1a621 Mon Sep 17 00:00:00 2001 From: David Steele <565205+davesteele@users.noreply.github.com> Date: Sun, 14 Dec 2025 21:05:22 -0500 Subject: [PATCH 08/16] Update Lib/argparse.py Co-authored-by: Savannah Ostrowski --- Lib/argparse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index aa1c87ed41f494..01582c23d145e7 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -765,8 +765,8 @@ def _split_lines(self, text, width): return self._para_reformat(text, width) def _fill_text(self, text, width, indent): - lines = self._para_reformat(text, width) - return "\n".join(lines) + lines = self._para_reformat(text, width - len(indent)) + return "\n".join(indent + line for line in lines) def _indents(self, line): """Return line indent level and "sub_indent" for bullet list text.""" From 329d906f8aed60b8c0272d44a2598134ceab8b88 Mon Sep 17 00:00:00 2001 From: David Steele <565205+davesteele@users.noreply.github.com> Date: Sun, 14 Dec 2025 21:06:58 -0500 Subject: [PATCH 09/16] Update Doc/library/argparse.rst Co-authored-by: Savannah Ostrowski --- Doc/library/argparse.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 37b13d768f9226..8de3e233511254 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -365,8 +365,8 @@ newlines. :class:`FlexiHelpFormatter` wraps description and help text like the default formatter, while preserving paragraphs and supporting bulleted lists. Bullet -list items are marked by the use of the "*", "-", "+", or ">" characters, or a -single non-whitespace character followed by a ".":: +list items are recognized by markers such as "*", "-", "+", or ">" characters, or +by alphanumeric sequences followed by "." or ")" (e.g. 1., a), iv.):: >>> parser = argparse.ArgumentParser( ... prog='PROG', From ae7c70f43bb841f2c2aba74d9be71e10ea1402f4 Mon Sep 17 00:00:00 2001 From: David Steele <565205+davesteele@users.noreply.github.com> Date: Sun, 14 Dec 2025 21:07:53 -0500 Subject: [PATCH 10/16] Update Doc/library/argparse.rst Co-authored-by: Savannah Ostrowski --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 8de3e233511254..f9ac71a060d1cd 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -390,7 +390,7 @@ by alphanumeric sequences followed by "." or ")" (e.g. 1., a), iv.):: ... * See? ... """) >>> parser.print_help() - usage: PROG [-h] option + usage: PROG [-h] argument The FlexiHelpFormatter will wrap text within paragraphs when required to in order to make the text fit. From f64e966b4b039c78c7fff148c347780cd2a4c766 Mon Sep 17 00:00:00 2001 From: David Steele <565205+davesteele@users.noreply.github.com> Date: Sun, 14 Dec 2025 21:08:24 -0500 Subject: [PATCH 11/16] Update Doc/library/argparse.rst Co-authored-by: Savannah Ostrowski --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index f9ac71a060d1cd..f4b2c45887ea55 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -407,7 +407,7 @@ by alphanumeric sequences followed by "." or ")" (e.g. 1., a), iv.):: wrap: * See? - optional arguments: + options: -h, --help show this help message and exit From 46e5e13807756521f5ad76550d923d565dfea5ef Mon Sep 17 00:00:00 2001 From: David Steele Date: Wed, 17 Dec 2025 11:31:56 -0500 Subject: [PATCH 12/16] Fix ParagraphHelpFormatter test --- Lib/test/test_argparse.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index f311ad8e0704c6..8cfc8210d185aa 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5465,11 +5465,11 @@ class TestHelpFlexi(HelpTestCase): * bullet title: - short help text - - Longer help text, containing useful contextual information for the var in - question - * and a bullet + short help text + + Longer help text, containing useful contextual information for the var in + question + * and a bullet --bar BAR bar help ''' From d45028d63e4c7ee2d5b9684870450adb7b4e743f Mon Sep 17 00:00:00 2001 From: David Steele Date: Thu, 18 Dec 2025 23:46:26 -0500 Subject: [PATCH 13/16] Avoid whitespace-only lines in _fill_text() It led to headaches in unittest. --- Lib/argparse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 01582c23d145e7..96d1778ba28327 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -766,7 +766,8 @@ def _split_lines(self, text, width): def _fill_text(self, text, width, indent): lines = self._para_reformat(text, width - len(indent)) - return "\n".join(indent + line for line in lines) + linearray = [indent + line if line else "" for line in lines] + return "\n".join(linearray) def _indents(self, line): """Return line indent level and "sub_indent" for bullet list text.""" From 86192826a0156958f86eadbb24c819894cd1b77d Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 19 Dec 2025 00:40:49 -0500 Subject: [PATCH 14/16] Lint fixes in argparse --- Doc/library/argparse.rst | 2 +- Lib/test/test_argparse.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index f4b2c45887ea55..6874f8f3e79ab4 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -365,7 +365,7 @@ newlines. :class:`FlexiHelpFormatter` wraps description and help text like the default formatter, while preserving paragraphs and supporting bulleted lists. Bullet -list items are recognized by markers such as "*", "-", "+", or ">" characters, or +list items are recognized by markers such as "*", "-", "+", or ">" characters, or by alphanumeric sequences followed by "." or ")" (e.g. 1., a), iv.):: >>> parser = argparse.ArgumentParser( diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 8cfc8210d185aa..7b0432a7146d09 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5466,7 +5466,7 @@ class TestHelpFlexi(HelpTestCase): title: short help text - + Longer help text, containing useful contextual information for the var in question * and a bullet From 2b30019d25f23980abc6533aae58eba3ded6e8c5 Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 19 Dec 2025 13:07:52 -0500 Subject: [PATCH 15/16] Rename FlexiHelpFormatter->ParagraphHelpFormatter --- Doc/library/argparse.rst | 23 ++++++++++--------- Lib/argparse.py | 4 ++-- Lib/test/test_argparse.py | 6 ++--- .../2020-09-07-00-00-51.bpo-12806.j1A_9o.rst | 2 +- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 6874f8f3e79ab4..e4f91e23b77e83 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -297,17 +297,17 @@ formatter_class ^^^^^^^^^^^^^^^ :class:`ArgumentParser` objects allow the help formatting to be customized by -specifying an alternate formatting class. Currently, there are four such +specifying an alternate formatting class. Currently, there are five such classes: .. class:: RawDescriptionHelpFormatter RawTextHelpFormatter - FlexiHelpFormatter + ParagraphHelpFormatter ArgumentDefaultsHelpFormatter MetavarTypeHelpFormatter :class:`RawDescriptionHelpFormatter`, :class:`RawTextHelpFormatter`, and -:class:`FlexiHelpFormatter` give more control over how textual descriptions +:class:`ParagraphHelpFormatter` give more control over how textual descriptions are displayed. By default, :class:`ArgumentParser` objects line-wrap the description_ and epilog_ texts in command-line help messages:: @@ -363,16 +363,17 @@ including argument descriptions. However, multiple newlines are replaced with one. If you wish to preserve multiple blank lines, add spaces between the newlines. -:class:`FlexiHelpFormatter` wraps description and help text like the default -formatter, while preserving paragraphs and supporting bulleted lists. Bullet -list items are recognized by markers such as "*", "-", "+", or ">" characters, or -by alphanumeric sequences followed by "." or ")" (e.g. 1., a), iv.):: +:class:`ParagraphHelpFormatter` wraps description and help text like the +default formatter, while preserving paragraphs and supporting bulleted lists. +Bullet list items are recognized by markers such as "*", "-", "+", or ">" +characters, or by alphanumeric sequences followed by "." or ")" (e.g. 1., a), +iv.):: >>> parser = argparse.ArgumentParser( ... prog='PROG', - ... formatter_class=argparse.FlexiHelpFormatter, + ... formatter_class=argparse.ParagraphHelpFormatter, ... description=""" - ... The FlexiHelpFormatter will wrap text within paragraphs + ... The ParagraphHelpFormatter will wrap text within paragraphs ... when required to in order to make the text fit. ... ... Paragraphs are preserved. @@ -392,7 +393,7 @@ by alphanumeric sequences followed by "." or ")" (e.g. 1., a), iv.):: >>> parser.print_help() usage: PROG [-h] argument - The FlexiHelpFormatter will wrap text within paragraphs when required to in + The ParagraphHelpFormatter will wrap text within paragraphs when required to in order to make the text fit. Paragraphs are preserved. @@ -412,7 +413,7 @@ by alphanumeric sequences followed by "." or ")" (e.g. 1., a), iv.):: .. versionadded:: 3.15 - :class:`FlexiHelpFormatter` class was added. + :class:`ParagraphHelpFormatter` class was added. :class:`ArgumentDefaultsHelpFormatter` automatically adds information about default values to each of the argument help messages:: diff --git a/Lib/argparse.py b/Lib/argparse.py index 96d1778ba28327..9565c01d08c698 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -74,7 +74,7 @@ 'ArgumentDefaultsHelpFormatter', 'RawDescriptionHelpFormatter', 'RawTextHelpFormatter', - 'FlexiHelpFormatter', + 'ParagraphHelpFormatter', 'MetavarTypeHelpFormatter', 'Namespace', 'Action', @@ -754,7 +754,7 @@ def _split_lines(self, text, width): return text.splitlines() -class FlexiHelpFormatter(HelpFormatter): +class ParagraphHelpFormatter(HelpFormatter): """Help message formatter which respects paragraphs and bulleted lists. Only the name of this class is considered a public API. All the methods diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 7b0432a7146d09..16673beb1d14e3 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5409,11 +5409,11 @@ class TestHelpRawDescription(HelpTestCase): version = '' -class TestHelpFlexi(HelpTestCase): - """Test the FlexiHelpFormatter""" +class TestHelpParagraph(HelpTestCase): + """Test the ParagraphHelpFormatter""" parser_signature = Sig( - prog='PROG', formatter_class=argparse.FlexiHelpFormatter, + prog='PROG', formatter_class=argparse.ParagraphHelpFormatter, description='This text should be wrapped as appropriate to keep\n' 'things nice and very, very tidy.\n' '\n' diff --git a/Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst b/Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst index e74b4a05e4cc4f..5c23d81df57aeb 100644 --- a/Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst +++ b/Misc/NEWS.d/next/Library/2020-09-07-00-00-51.bpo-12806.j1A_9o.rst @@ -1,3 +1,3 @@ -The :mod:`argparse` module has a new :class:`argparse.FlexiHelpFormatter` +The :mod:`argparse` module has a new :class:`argparse.ParagraphHelpFormatter` class that wraps help and description text while preserving paragraphs and supporting bulleted lists. From ec6d2d78d1fac910c25eba34e1790fdae212d30f Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 19 Dec 2025 13:34:12 -0500 Subject: [PATCH 16/16] Clarify paragraph def for ParagraphHelpFormatter --- Doc/library/argparse.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index e4f91e23b77e83..e8cf2c2387b287 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -364,10 +364,13 @@ one. If you wish to preserve multiple blank lines, add spaces between the newlines. :class:`ParagraphHelpFormatter` wraps description and help text like the -default formatter, while preserving paragraphs and supporting bulleted lists. -Bullet list items are recognized by markers such as "*", "-", "+", or ">" -characters, or by alphanumeric sequences followed by "." or ")" (e.g. 1., a), -iv.):: +default formatter, while preserving paragraphs. Parapgraphs are separated by +blank lines. Blocks of text separated by a single return are merged into a +single paragraph. + +Bullet lists are supported. Text for a bullet item is wrapped with appropriate +indentation. Bullet list items are recognized by markers such as "*", "-", "+", +or ">" characters, or by alphanumeric sequences followed by "." or ")".:: >>> parser = argparse.ArgumentParser( ... prog='PROG',