Commit f4511124 authored by Serhiy Storchaka's avatar Serhiy Storchaka

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.
parent 32c4915b
...@@ -165,6 +165,8 @@ class HelpFormatter(object): ...@@ -165,6 +165,8 @@ class HelpFormatter(object):
self._prog = prog self._prog = prog
self._indent_increment = indent_increment self._indent_increment = indent_increment
self._max_help_position = max_help_position 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._width = width
self._current_indent = 0 self._current_indent = 0
...@@ -336,7 +338,7 @@ class HelpFormatter(object): ...@@ -336,7 +338,7 @@ class HelpFormatter(object):
else: else:
line_len = len(indent) - 1 line_len = len(indent) - 1
for part in parts: 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)) lines.append(indent + ' '.join(line))
line = [] line = []
line_len = len(indent) - 1 line_len = len(indent) - 1
...@@ -476,7 +478,7 @@ class HelpFormatter(object): ...@@ -476,7 +478,7 @@ class HelpFormatter(object):
def _format_text(self, text): def _format_text(self, text):
if '%(prog)' in text: if '%(prog)' in text:
text = text % dict(prog=self._prog) 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 indent = ' ' * self._current_indent
return self._fill_text(text, text_width, indent) + '\n\n' return self._fill_text(text, text_width, indent) + '\n\n'
...@@ -484,7 +486,7 @@ class HelpFormatter(object): ...@@ -484,7 +486,7 @@ class HelpFormatter(object):
# determine the required width and the entry label # determine the required width and the entry label
help_position = min(self._action_max_length + 2, help_position = min(self._action_max_length + 2,
self._max_help_position) 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_width = help_position - self._current_indent - 2
action_header = self._format_action_invocation(action) action_header = self._format_action_invocation(action)
......
...@@ -209,7 +209,6 @@ class HelpFormatter: ...@@ -209,7 +209,6 @@ class HelpFormatter:
short_first): short_first):
self.parser = None self.parser = None
self.indent_increment = indent_increment self.indent_increment = indent_increment
self.help_position = self.max_help_position = max_help_position
if width is None: if width is None:
try: try:
width = int(os.environ['COLUMNS']) width = int(os.environ['COLUMNS'])
...@@ -217,6 +216,8 @@ class HelpFormatter: ...@@ -217,6 +216,8 @@ class HelpFormatter:
width = 80 width = 80
width -= 2 width -= 2
self.width = width 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.current_indent = 0
self.level = 0 self.level = 0
self.help_width = None # computed later self.help_width = None # computed later
...@@ -261,7 +262,7 @@ class HelpFormatter: ...@@ -261,7 +262,7 @@ class HelpFormatter:
Format a paragraph of free-form text for inclusion in the Format a paragraph of free-form text for inclusion in the
help output at the current indentation level. 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 indent = " "*self.current_indent
return textwrap.fill(text, return textwrap.fill(text,
text_width, text_width,
...@@ -342,7 +343,7 @@ class HelpFormatter: ...@@ -342,7 +343,7 @@ class HelpFormatter:
self.dedent() self.dedent()
self.dedent() self.dedent()
self.help_position = min(max_len + 2, self.max_help_position) 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): def format_option_strings(self, option):
"""Return a comma-separated list of option strings & metavariables.""" """Return a comma-separated list of option strings & metavariables."""
......
...@@ -2973,6 +2973,60 @@ class TestHelpBiggerOptionals(HelpTestCase): ...@@ -2973,6 +2973,60 @@ class TestHelpBiggerOptionals(HelpTestCase):
0.1 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): class TestHelpBiggerOptionalGroups(HelpTestCase):
"""Make sure that argument help aligns when options are longer""" """Make sure that argument help aligns when options are longer"""
......
...@@ -1443,6 +1443,39 @@ Options: ...@@ -1443,6 +1443,39 @@ Options:
-h, --help show this help message and exit -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): class TestHelp(BaseTest):
def setUp(self): def setUp(self):
self.parser = self.make_parser(80) self.parser = self.make_parser(80)
...@@ -1500,6 +1533,8 @@ class TestHelp(BaseTest): ...@@ -1500,6 +1533,8 @@ class TestHelp(BaseTest):
# we look at $COLUMNS. # we look at $COLUMNS.
self.parser = self.make_parser(60) self.parser = self.make_parser(60)
self.assertHelpEquals(_expected_help_short_lines) self.assertHelpEquals(_expected_help_short_lines)
self.parser = self.make_parser(0)
self.assertHelpEquals(_expected_very_help_short_lines)
def test_help_unicode(self): def test_help_unicode(self):
self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
......
...@@ -430,6 +430,7 @@ Marius Gedminas ...@@ -430,6 +430,7 @@ Marius Gedminas
Thomas Gellekum Thomas Gellekum
Gabriel Genellina Gabriel Genellina
Christos Georgiou Christos Georgiou
Elazar Gershuni
Ben Gertzfield Ben Gertzfield
Nadim Ghaznavi Nadim Ghaznavi
Dinu Gherman Dinu Gherman
......
...@@ -43,6 +43,10 @@ Core and Builtins ...@@ -43,6 +43,10 @@ Core and Builtins
Library 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 - Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly
asked for. asked for.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment