]> granicus.if.org Git - python/commitdiff
Issue #13107: argparse and optparse no longer raises an exception when output
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 9 Jan 2014 21:14:27 +0000 (23:14 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Thu, 9 Jan 2014 21:14:27 +0000 (23:14 +0200)
a help on environment with too small COLUMNS.  Based on patch by
Elazar Gershuni.

Lib/argparse.py
Lib/optparse.py
Lib/test/test_argparse.py
Lib/test/test_optparse.py
Misc/ACKS
Misc/NEWS

index f25b1b66109596f0646d4743fd9101ce3c62dd05..bc2ba132eddc82671bc728f2b96607943a0f146e 100644 (file)
@@ -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)
 
index 22405d5eb8be59df8a24cb0de3167cd7cc7f24ad..be0145f353db2e5c8eade5977ab9498c36327b8d 100644 (file)
@@ -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."""
index c06c940bf2d62dcccbc4bdb3de3fbf8f1192d2fe..9cb15c78bda97bed6c7fc6d63150819aeea9edf5 100644 (file)
@@ -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"""
index 78de278f76ef524e426b201b60efbe8bab7f0639..eaee504ac8849b171ccdc92651f08859a043fea2 100644 (file)
@@ -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)
index bb469ae2987f0ad43a44c324b9a8f44d837854cd..cea4bedde37d4a21ed32c80b6469f165b501c73e 100644 (file)
--- 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
index 1fcae77b42ed0cdb7e298b0972c837d277282d0c..220289d9b1187943c40138a3dde60e208fffa252 100644 (file)
--- 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.