From f451112413b9ea8940c8c3a902cddf701c62d17f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 9 Jan 2014 23:14:27 +0200 Subject: Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by Elazar Gershuni. --- Lib/argparse.py | 8 ++++--- Lib/optparse.py | 7 +++--- Lib/test/test_argparse.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++ Lib/test/test_optparse.py | 35 ++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 6 files changed, 103 insertions(+), 6 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index f25b1b6..bc2ba13 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -165,6 +165,8 @@ class HelpFormatter(object): self._prog = prog self._indent_increment = indent_increment self._max_help_position = max_help_position + self._max_help_position = min(max_help_position, + max(width - 20, indent_increment * 2)) self._width = width self._current_indent = 0 @@ -336,7 +338,7 @@ class HelpFormatter(object): else: line_len = len(indent) - 1 for part in parts: - if line_len + 1 + len(part) > text_width: + if line_len + 1 + len(part) > text_width and line: lines.append(indent + ' '.join(line)) line = [] line_len = len(indent) - 1 @@ -476,7 +478,7 @@ class HelpFormatter(object): def _format_text(self, text): if '%(prog)' in text: text = text % dict(prog=self._prog) - text_width = self._width - self._current_indent + text_width = max(self._width - self._current_indent, 11) indent = ' ' * self._current_indent return self._fill_text(text, text_width, indent) + '\n\n' @@ -484,7 +486,7 @@ class HelpFormatter(object): # determine the required width and the entry label help_position = min(self._action_max_length + 2, self._max_help_position) - help_width = self._width - help_position + help_width = max(self._width - help_position, 11) action_width = help_position - self._current_indent - 2 action_header = self._format_action_invocation(action) diff --git a/Lib/optparse.py b/Lib/optparse.py index 22405d5..be0145f 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -209,7 +209,6 @@ class HelpFormatter: short_first): self.parser = None self.indent_increment = indent_increment - self.help_position = self.max_help_position = max_help_position if width is None: try: width = int(os.environ['COLUMNS']) @@ -217,6 +216,8 @@ class HelpFormatter: width = 80 width -= 2 self.width = width + self.help_position = self.max_help_position = \ + min(max_help_position, max(width - 20, indent_increment * 2)) self.current_indent = 0 self.level = 0 self.help_width = None # computed later @@ -261,7 +262,7 @@ class HelpFormatter: Format a paragraph of free-form text for inclusion in the help output at the current indentation level. """ - text_width = self.width - self.current_indent + text_width = max(self.width - self.current_indent, 11) indent = " "*self.current_indent return textwrap.fill(text, text_width, @@ -342,7 +343,7 @@ class HelpFormatter: self.dedent() self.dedent() self.help_position = min(max_len + 2, self.max_help_position) - self.help_width = self.width - self.help_position + self.help_width = max(self.width - self.help_position, 11) def format_option_strings(self, option): """Return a comma-separated list of option strings & metavariables.""" diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index c06c940..9cb15c7 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2973,6 +2973,60 @@ class TestHelpBiggerOptionals(HelpTestCase): 0.1 ''' +class TestShortColumns(HelpTestCase): + '''Test extremely small number of columns. + + TestCase prevents "COLUMNS" from being too small in the tests themselves, + but we don't want any exceptions thrown in such case. Only ugly representation. + ''' + def setUp(self): + env = support.EnvironmentVarGuard() + env.set("COLUMNS", '15') + self.addCleanup(env.__exit__) + + parser_signature = TestHelpBiggerOptionals.parser_signature + argument_signatures = TestHelpBiggerOptionals.argument_signatures + argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures + usage = '''\ + usage: PROG + [-h] + [-v] + [-x] + [--y Y] + foo + bar + ''' + help = usage + '''\ + + DESCRIPTION + + positional arguments: + foo + FOO HELP + bar + BAR HELP + + optional arguments: + -h, --help + show this + help + message and + exit + -v, --version + show + program's + version + number and + exit + -x + X HELP + --y Y + Y HELP + + EPILOG + ''' + version = TestHelpBiggerOptionals.version + class TestHelpBiggerOptionalGroups(HelpTestCase): """Make sure that argument help aligns when options are longer""" diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py index 78de278..eaee504 100644 --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -1443,6 +1443,39 @@ Options: -h, --help show this help message and exit """ +_expected_very_help_short_lines = """\ +Usage: bar.py [options] + +Options: + -a APPLE + throw + APPLEs at + basket + -b NUM, --boo=NUM + shout + "boo!" NUM + times (in + order to + frighten + away all + the evil + spirits + that cause + trouble and + mayhem) + --foo=FOO + store FOO + in the foo + list for + later + fooing + -h, --help + show this + help + message and + exit +""" + class TestHelp(BaseTest): def setUp(self): self.parser = self.make_parser(80) @@ -1500,6 +1533,8 @@ class TestHelp(BaseTest): # we look at $COLUMNS. self.parser = self.make_parser(60) self.assertHelpEquals(_expected_help_short_lines) + self.parser = self.make_parser(0) + self.assertHelpEquals(_expected_very_help_short_lines) def test_help_unicode(self): self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) diff --git a/Misc/ACKS b/Misc/ACKS index bb469ae..cea4bed 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -430,6 +430,7 @@ Marius Gedminas Thomas Gellekum Gabriel Genellina Christos Georgiou +Elazar Gershuni Ben Gertzfield Nadim Ghaznavi Dinu Gherman diff --git a/Misc/NEWS b/Misc/NEWS index 1fcae77..220289d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,10 @@ Core and Builtins Library ------- +- Issue #13107: argparse and optparse no longer raises an exception when output + a help on environment with too small COLUMNS. Based on patch by + Elazar Gershuni. + - Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly asked for. -- cgit v0.12