From dd7ef9de540e2b0ab46ff6ba6656156fd1e73493 Mon Sep 17 00:00:00 2001 From: "Franklin, Samuel" Date: Wed, 21 Aug 2019 18:30:57 -0400 Subject: [PATCH 1/7] bpo-37910: argparse usage wrapping should not fail on whitespace differences. Stripping whitespace in the opt_ and pos_usage assertions solves this issue, which can be introduced by empty metavars or metavars containing various forms of whitespace. --- Lib/argparse.py | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index a300828f9e3d2e..659415dffc489f 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -103,6 +103,7 @@ # Utility functions and classes # ============================= + class _AttributeHolder(object): """Abstract base class that provides __repr__. @@ -140,7 +141,7 @@ def _copy_items(items): # The copy module is used only in the 'append' and 'append_const' # actions, and it is needed only when the default value isn't a list. # Delay its import for speeding up the common case. - if type(items) is list: + if isinstance(items, list): return items[:] import copy return copy.copy(items) @@ -333,8 +334,11 @@ def _format_usage(self, usage, actions, groups, prefix): pos_usage = format(positionals, groups) opt_parts = _re.findall(part_regexp, opt_usage) pos_parts = _re.findall(part_regexp, pos_usage) - assert ' '.join(opt_parts) == opt_usage - assert ' '.join(pos_parts) == pos_usage + + # ignore extra whitespace differences + # can happen if metavar='', '\n', or '\t' + assert ' '.join(opt_parts).split() == opt_usage.split() + assert ' '.join(pos_parts).split() == pos_usage.split() # helper for wrapping lines def get_lines(parts, indent, prefix=None): @@ -655,7 +659,8 @@ class RawDescriptionHelpFormatter(HelpFormatter): """ def _fill_text(self, text, width, indent): - return ''.join(indent + line for line in text.splitlines(keepends=True)) + return ''.join( + indent + line for line in text.splitlines(keepends=True)) class RawTextHelpFormatter(RawDescriptionHelpFormatter): @@ -701,7 +706,6 @@ def _get_default_metavar_for_positional(self, action): return action.type.__name__ - # ===================== # Options and Arguments # ===================== @@ -710,7 +714,7 @@ def _get_action_name(argument): if argument is None: return None elif argument.option_strings: - return '/'.join(argument.option_strings) + return '/'.join(argument.option_strings) elif argument.metavar not in (None, SUPPRESS): return argument.metavar elif argument.dest not in (None, SUPPRESS): @@ -1157,6 +1161,7 @@ def __call__(self, parser, namespace, values, option_string=None): vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, []) getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) + class _ExtendAction(_AppendAction): def __call__(self, parser, namespace, values, option_string=None): items = getattr(namespace, self.dest, None) @@ -1168,6 +1173,7 @@ def __call__(self, parser, namespace, values, option_string=None): # Type classes # ============== + class FileType(object): """Factory for creating file object types @@ -1222,6 +1228,7 @@ def __repr__(self): # Optional and Positional Parsing # =========================== + class Namespace(_AttributeHolder): """Simple object for storing attributes. @@ -1322,10 +1329,10 @@ def get_default(self, dest): return action.default return self._defaults.get(dest, None) - # ======================= # Adding argument actions # ======================= + def add_argument(self, *args, **kwargs): """ add_argument(dest, ..., name=value, ...) @@ -1373,7 +1380,8 @@ def add_argument(self, *args, **kwargs): try: self._get_formatter()._format_args(action, None) except TypeError: - raise ValueError("length of metavar tuple does not match nargs") + raise ValueError( + "length of metavar tuple does not match nargs") return self._add_action(action) @@ -1482,7 +1490,8 @@ def _get_optional_kwargs(self, *args, **kwargs): # strings starting with two prefix characters are long options option_strings.append(option_string) - if len(option_string) > 1 and option_string[1] in self.prefix_chars: + if len( + option_string) > 1 and option_string[1] in self.prefix_chars: long_option_strings.append(option_string) # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' @@ -1672,7 +1681,7 @@ def identity(string): default_prefix = '-' if '-' in prefix_chars else prefix_chars[0] if self.add_help: self.add_argument( - default_prefix+'h', default_prefix*2+'help', + default_prefix + 'h', default_prefix * 2 + 'help', action='help', default=SUPPRESS, help=_('show this help message and exit')) @@ -2016,7 +2025,7 @@ def consume_positionals(start_index): if (action.default is not None and isinstance(action.default, str) and hasattr(namespace, action.dest) and - action.default is getattr(namespace, action.dest)): + action.default is getattr(namespace, action.dest)): setattr(namespace, action.dest, self._get_value(action, action.default)) @@ -2141,7 +2150,7 @@ def _parse_optional(self, arg_string): # if multiple actions match, the option string was ambiguous if len(option_tuples) > 1: options = ', '.join([option_string - for action, option_string, explicit_arg in option_tuples]) + for action, option_string, explicit_arg in option_tuples]) args = {'option': arg_string, 'matches': options} msg = _('ambiguous option: %(option)s could match %(matches)s') self.error(msg % args) @@ -2285,10 +2294,10 @@ def parse_known_intermixed_args(self, args=None, namespace=None): if action.nargs in [PARSER, REMAINDER]] if a: raise TypeError('parse_intermixed_args: positional arg' - ' with nargs=%s'%a[0].nargs) + ' with nargs=%s' % a[0].nargs) if [action.dest for group in self._mutually_exclusive_groups - for action in group._group_actions if action in positionals]: + for action in group._group_actions if action in positionals]: raise TypeError('parse_intermixed_args: positional in' ' mutuallyExclusiveGroup') @@ -2310,9 +2319,11 @@ def parse_known_intermixed_args(self, args=None, namespace=None): for action in positionals: # remove the empty positional values from namespace if (hasattr(namespace, action.dest) - and getattr(namespace, action.dest)==[]): + and getattr(namespace, action.dest) == []): from warnings import warn - warn('Do not expect %s in %s' % (action.dest, namespace)) + warn( + 'Do not expect %s in %s' % + (action.dest, namespace)) delattr(namespace, action.dest) finally: # restore nargs and usage before exiting From 41e22bfb726d47677fa7d06dd4cc4ef9c5605831 Mon Sep 17 00:00:00 2001 From: "Franklin, Samuel" Date: Wed, 21 Aug 2019 18:48:00 -0400 Subject: [PATCH 2/7] revert accidental automatic PEP8 changes --- Lib/argparse.py | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 659415dffc489f..f479b4c3061b18 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -103,7 +103,6 @@ # Utility functions and classes # ============================= - class _AttributeHolder(object): """Abstract base class that provides __repr__. @@ -141,7 +140,7 @@ def _copy_items(items): # The copy module is used only in the 'append' and 'append_const' # actions, and it is needed only when the default value isn't a list. # Delay its import for speeding up the common case. - if isinstance(items, list): + if type(items) is list: return items[:] import copy return copy.copy(items) @@ -659,8 +658,7 @@ class RawDescriptionHelpFormatter(HelpFormatter): """ def _fill_text(self, text, width, indent): - return ''.join( - indent + line for line in text.splitlines(keepends=True)) + return ''.join(indent + line for line in text.splitlines(keepends=True)) class RawTextHelpFormatter(RawDescriptionHelpFormatter): @@ -706,6 +704,7 @@ def _get_default_metavar_for_positional(self, action): return action.type.__name__ + # ===================== # Options and Arguments # ===================== @@ -714,7 +713,7 @@ def _get_action_name(argument): if argument is None: return None elif argument.option_strings: - return '/'.join(argument.option_strings) + return '/'.join(argument.option_strings) elif argument.metavar not in (None, SUPPRESS): return argument.metavar elif argument.dest not in (None, SUPPRESS): @@ -1161,7 +1160,6 @@ def __call__(self, parser, namespace, values, option_string=None): vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, []) getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) - class _ExtendAction(_AppendAction): def __call__(self, parser, namespace, values, option_string=None): items = getattr(namespace, self.dest, None) @@ -1173,7 +1171,6 @@ def __call__(self, parser, namespace, values, option_string=None): # Type classes # ============== - class FileType(object): """Factory for creating file object types @@ -1228,7 +1225,6 @@ def __repr__(self): # Optional and Positional Parsing # =========================== - class Namespace(_AttributeHolder): """Simple object for storing attributes. @@ -1329,10 +1325,10 @@ def get_default(self, dest): return action.default return self._defaults.get(dest, None) + # ======================= # Adding argument actions # ======================= - def add_argument(self, *args, **kwargs): """ add_argument(dest, ..., name=value, ...) @@ -1380,8 +1376,7 @@ def add_argument(self, *args, **kwargs): try: self._get_formatter()._format_args(action, None) except TypeError: - raise ValueError( - "length of metavar tuple does not match nargs") + raise ValueError("length of metavar tuple does not match nargs") return self._add_action(action) @@ -1490,8 +1485,7 @@ def _get_optional_kwargs(self, *args, **kwargs): # strings starting with two prefix characters are long options option_strings.append(option_string) - if len( - option_string) > 1 and option_string[1] in self.prefix_chars: + if len(option_string) > 1 and option_string[1] in self.prefix_chars: long_option_strings.append(option_string) # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' @@ -1681,7 +1675,7 @@ def identity(string): default_prefix = '-' if '-' in prefix_chars else prefix_chars[0] if self.add_help: self.add_argument( - default_prefix + 'h', default_prefix * 2 + 'help', + default_prefix+'h', default_prefix*2+'help', action='help', default=SUPPRESS, help=_('show this help message and exit')) @@ -2025,7 +2019,7 @@ def consume_positionals(start_index): if (action.default is not None and isinstance(action.default, str) and hasattr(namespace, action.dest) and - action.default is getattr(namespace, action.dest)): + action.default is getattr(namespace, action.dest)): setattr(namespace, action.dest, self._get_value(action, action.default)) @@ -2150,7 +2144,7 @@ def _parse_optional(self, arg_string): # if multiple actions match, the option string was ambiguous if len(option_tuples) > 1: options = ', '.join([option_string - for action, option_string, explicit_arg in option_tuples]) + for action, option_string, explicit_arg in option_tuples]) args = {'option': arg_string, 'matches': options} msg = _('ambiguous option: %(option)s could match %(matches)s') self.error(msg % args) @@ -2294,10 +2288,10 @@ def parse_known_intermixed_args(self, args=None, namespace=None): if action.nargs in [PARSER, REMAINDER]] if a: raise TypeError('parse_intermixed_args: positional arg' - ' with nargs=%s' % a[0].nargs) + ' with nargs=%s'%a[0].nargs) if [action.dest for group in self._mutually_exclusive_groups - for action in group._group_actions if action in positionals]: + for action in group._group_actions if action in positionals]: raise TypeError('parse_intermixed_args: positional in' ' mutuallyExclusiveGroup') @@ -2319,11 +2313,9 @@ def parse_known_intermixed_args(self, args=None, namespace=None): for action in positionals: # remove the empty positional values from namespace if (hasattr(namespace, action.dest) - and getattr(namespace, action.dest) == []): + and getattr(namespace, action.dest)==[]): from warnings import warn - warn( - 'Do not expect %s in %s' % - (action.dest, namespace)) + warn('Do not expect %s in %s' % (action.dest, namespace)) delattr(namespace, action.dest) finally: # restore nargs and usage before exiting From fcf7d427c788038b44d52b7233ceeb93fcdb07dd Mon Sep 17 00:00:00 2001 From: "Franklin, Samuel" Date: Thu, 19 Sep 2019 23:43:37 -0400 Subject: [PATCH 3/7] added unit tests for now allowable metavar characters including nearly all Unicode whitespace characters. Thank you Ashwin Ramaswami for the recommendation. --- Lib/test/test_argparse.py | 211 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index a97c921852c7bf..b7c64687c92ffb 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5224,6 +5224,191 @@ def test_nargs_3_metavar_length3(self): self.do_test_no_exception(nargs=3, metavar=("1", "2", "3")) +class TestAddArgumentMetavarWrapNoException(TestCase): + """Check that certain special character wrap with no exceptions + Based off TestAddArgumentMetavar""" + + def do_test_no_exception(self, metavar): + parser = argparse.ArgumentParser(prog='PROG' * 19) # force wrapping + parser.add_argument("--foo", metavar=metavar) + + def test_metavar_nil(self): + self.do_test_no_exception(metavar='') + + def test_metavar_space(self): + self.do_test_no_exception(metavar=' ') + + def test_metavar_Line_Feed(self): + self.do_test_no_exception(metavar='\n') + + def test_metavar_Tab(self): + self.do_test_no_exception(metavar='\t') + + def test_metavar_Carriage_Return(self): + self.do_test_no_exception(metavar='\r') + + def test_metavar_Carriage_Return_and_Line_Feed(self): + self.do_test_no_exception(metavar='\r\n') + + # The rest would be unlikely in practice but should not fail + + def test_metavar_vLine_Tabulation(self): + self.do_test_no_exception(metavar='\v') + + def test_metavar_x0b_Line_Tabulation(self): + self.do_test_no_exception(metavar='\x0b') + + def test_metavar_f_Form_Feed(self): + self.do_test_no_exception(metavar='\f') + + def test_metavar_x0c_Form_Feed(self): + self.do_test_no_exception(metavar='\x0c') + + def test_metavar_File_Separator(self): + self.do_test_no_exception(metavar='\x1c') + + def test_metavar_Group_Separator(self): + self.do_test_no_exception(metavar='\x1d') + + def test_metavar_Record_Separator(self): + self.do_test_no_exception(metavar='\x1e') + + def test_metavar_C1_Control_Code(self): + self.do_test_no_exception(metavar='\x85') + + def test_metavar_Line_Separator(self): + self.do_test_no_exception(metavar='\u2028') + + def test_metavar_Paragraph_Separator(self): + self.do_test_no_exception(metavar='\u2029') + + def test_metavar_backslash(self): + self.do_test_no_exception(metavar='\\') + + def test_metavar_single_quote(self): + self.do_test_no_exception(metavar='\'') + + def test_metavar_double_quote(self): + self.do_test_no_exception(metavar='\"') + + def test_metavar_ASCII_bell(self): + self.do_test_no_exception(metavar='\a') + + def test_metavar_ASCII_backspace(self): + self.do_test_no_exception(metavar='\b') + + # Unicode whitespaces per wikipedia.org/wiki/Whitespace_character + + def test_metavar_unicode_horizontal_tab(self): + self.do_test_no_exception(metavar='\u0009') + + def test_metavar_unicode_line_feed(self): + self.do_test_no_exception(metavar='\u000A') + + def test_metavar_unicode_vertical_tab(self): + self.do_test_no_exception(metavar='\u000B') + + def test_metavar_unicode_form_feed(self): + self.do_test_no_exception(metavar='\u000C') + + def test_metavar_unicode_carriage_return(self): + self.do_test_no_exception(metavar='\u000D') + + def test_metavar_unicode_space(self): + self.do_test_no_exception(metavar='\u0020') + + def test_metavar_unicode_next_line(self): + self.do_test_no_exception(metavar='\u0085') + + def test_metavar_unicode_non_breaking_space(self): + self.do_test_no_exception(metavar='\u00A0') + + def test_metavar_unicode_ogham_space_mark(self): + self.do_test_no_exception(metavar='\u1680') + + def test_metavar_unicode_en_quad(self): + self.do_test_no_exception(metavar='\u2000') + + def test_metavar_unicode_em_quad(self): + self.do_test_no_exception(metavar='\u2001') + + def test_metavar_unicode_en_space(self): + self.do_test_no_exception(metavar='\u2002') + + def test_metavar_unicode_em_space(self): + self.do_test_no_exception(metavar='\u2003') + + def test_metavar_unicode_three_per_em_space(self): + self.do_test_no_exception(metavar='\u2004') + + def test_metavar_unicode_four_per_em_space(self): + self.do_test_no_exception(metavar='\u2005') + + def test_metavar_unicode_six_per_em_space(self): + self.do_test_no_exception(metavar='\u2006') + + def test_metavar_unicode_figure_space(self): + self.do_test_no_exception(metavar='\u2007') + + def test_metavar_unicode_puctuation_space(self): + self.do_test_no_exception(metavar='\u2008') + + def test_metavar_unicode_thin_space(self): + self.do_test_no_exception(metavar='\u2009') + + def test_metavar_unicode_hair_space(self): + self.do_test_no_exception(metavar='\u200A') + + def test_metavar_unicode_line_separator(self): + self.do_test_no_exception(metavar='\u2028') + + def test_metavar_unicode_paragraph_separator(self): + self.do_test_no_exception(metavar='\u2029') + + def test_metavar_unicode_narrow_no_break_space(self): + self.do_test_no_exception(metavar='\u202F') + + def test_metavar_unicode_medium_mathematical_space(self): + self.do_test_no_exception(metavar='\u205F') + + def test_metavar_unicode_ideographic_space(self): + self.do_test_no_exception(metavar='\u3000') + + def test_metavar_unicode_mongolian_vowel_separator(self): + self.do_test_no_exception(metavar='\u180E') + + def test_metavar_unicode_zero_width_space(self): + self.do_test_no_exception(metavar='\u200B') + + def test_metavar_unicode_zero_width_non_joiner(self): + self.do_test_no_exception(metavar='\u200C') + + def test_metavar_unicode_zero_width_joiner(self): + self.do_test_no_exception(metavar='\u200D') + + def test_metavar_unicode_word_joiner(self): + self.do_test_no_exception(metavar='\u2060') + + def test_metavar_unicode_zero_width_non_breaking_space(self): + self.do_test_no_exception(metavar='\uFEFF') + + # visible 'whitespace' characters, mainly with typesetting usages. + def test_metavar_unicode_middle_dot(self): + self.do_test_no_exception(metavar='\u00B7') + + def test_metavar_unicode_shouldered_open_box(self): + self.do_test_no_exception(metavar='\u237D') + + def test_metavar_unicode_symbol_for_space(self): + self.do_test_no_exception(metavar='\u2420') + + def test_metavar_unicode_blank_symbol(self): + self.do_test_no_exception(metavar='\u2422') + + def test_metavar_unicode_open_box(self): + self.do_test_no_exception(metavar='\u2423') + + class TestInvalidNargs(TestCase): EXPECTED_INVALID_MESSAGE = "invalid nargs value" @@ -5296,6 +5481,32 @@ def test_help_with_metavar(self): ''')) +class TestHelpUsageWrapAllowsNilAndTab(HelpTestCase): + """Usage message should wrap successfully when metavar='' or literal tab + Other whitespace characters may behave differently on different systems, + but should not cause an assertion error.""" + + parser_signature = Sig(prog='PROG' * 19) + argument_signatures = [ + Sig('--nil', metavar=''), + Sig('--Tab', metavar='\ttab') + ] + argument_group_signatures = [] + usage = '''\ + usage: PROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROG + [-h] [--nil] [--Tab tab] + ''' + help = usage + '''\ + + optional arguments: + -h, --help show this help message and exit + --nil \ + + --Tab tab + ''' + version = '' + + class TestExitOnError(TestCase): def setUp(self): From 646fbade31f934b076c7ac8aaa852b68453ef434 Mon Sep 17 00:00:00 2001 From: "Franklin, Samuel" Date: Fri, 20 Sep 2019 00:23:59 -0400 Subject: [PATCH 4/7] bpo-37910: checks format_usage wrapping to ensure whitespaces do not break argparse usage help text --- Lib/test/test_argparse.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index b7c64687c92ffb..c78c09f0cc4819 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5231,6 +5231,7 @@ class TestAddArgumentMetavarWrapNoException(TestCase): def do_test_no_exception(self, metavar): parser = argparse.ArgumentParser(prog='PROG' * 19) # force wrapping parser.add_argument("--foo", metavar=metavar) + parser.format_usage() def test_metavar_nil(self): self.do_test_no_exception(metavar='') From 30c69ff20664f46b4ea9fd6f265aef590787363b Mon Sep 17 00:00:00 2001 From: "Franklin, Samuel" Date: Fri, 20 Sep 2019 00:40:19 -0400 Subject: [PATCH 5/7] bpo-37910: checks format_usage wrapping to ensure whitespaces do not break argparse usage help text. Fixed whitespace issue. --- Lib/test/test_argparse.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index c78c09f0cc4819..d0b8f5f1aeadfd 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5252,7 +5252,7 @@ def test_metavar_Carriage_Return_and_Line_Feed(self): self.do_test_no_exception(metavar='\r\n') # The rest would be unlikely in practice but should not fail - + def test_metavar_vLine_Tabulation(self): self.do_test_no_exception(metavar='\v') @@ -5299,7 +5299,7 @@ def test_metavar_ASCII_backspace(self): self.do_test_no_exception(metavar='\b') # Unicode whitespaces per wikipedia.org/wiki/Whitespace_character - + def test_metavar_unicode_horizontal_tab(self): self.do_test_no_exception(metavar='\u0009') @@ -5408,7 +5408,7 @@ def test_metavar_unicode_blank_symbol(self): def test_metavar_unicode_open_box(self): self.do_test_no_exception(metavar='\u2423') - + class TestInvalidNargs(TestCase): @@ -5506,7 +5506,7 @@ class TestHelpUsageWrapAllowsNilAndTab(HelpTestCase): --Tab tab ''' version = '' - + class TestExitOnError(TestCase): From ad76df556e313f54a0e10990023f602bea5cc38a Mon Sep 17 00:00:00 2001 From: "Franklin, Samuel" Date: Fri, 20 Sep 2019 01:09:16 -0400 Subject: [PATCH 6/7] bpo-37910: checks format_usage wrapping to ensure whitespaces do not break argparse usage help text. Fixed whitespace issue. --- .../next/Library/2019-09-20-01-08-53.bpo-37910.hxlo0G.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-09-20-01-08-53.bpo-37910.hxlo0G.rst diff --git a/Misc/NEWS.d/next/Library/2019-09-20-01-08-53.bpo-37910.hxlo0G.rst b/Misc/NEWS.d/next/Library/2019-09-20-01-08-53.bpo-37910.hxlo0G.rst new file mode 100644 index 00000000000000..216ed13a5392aa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-20-01-08-53.bpo-37910.hxlo0G.rst @@ -0,0 +1,3 @@ +argparse.py now allows metavar to be certain whitespace characters, such as +'' and '\t'. This fixes a bug where wrapping usage across multiple lines +would raise an assertion error. From d941a8538157477abb8fc2c0ded4235c1f5127d7 Mon Sep 17 00:00:00 2001 From: "Franklin, Samuel" Date: Fri, 20 Sep 2019 01:09:36 -0400 Subject: [PATCH 7/7] bpo-37910: checks format_usage wrapping to ensure whitespaces do not break argparse usage help text. Fixed whitespace issue. --- Lib/test/test_argparse.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index d0b8f5f1aeadfd..d01544a3311522 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5482,32 +5482,6 @@ def test_help_with_metavar(self): ''')) -class TestHelpUsageWrapAllowsNilAndTab(HelpTestCase): - """Usage message should wrap successfully when metavar='' or literal tab - Other whitespace characters may behave differently on different systems, - but should not cause an assertion error.""" - - parser_signature = Sig(prog='PROG' * 19) - argument_signatures = [ - Sig('--nil', metavar=''), - Sig('--Tab', metavar='\ttab') - ] - argument_group_signatures = [] - usage = '''\ - usage: PROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROGPROG - [-h] [--nil] [--Tab tab] - ''' - help = usage + '''\ - - optional arguments: - -h, --help show this help message and exit - --nil \ - - --Tab tab - ''' - version = '' - - class TestExitOnError(TestCase): def setUp(self):