classification
Title: Text width in optparse.py can become negative
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.4, Python 3.3, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: serhiy.storchaka Nosy List: adambyrtek, aronacher, bethard, dmi.baranov, elazar, ezio.melotti, python-dev, serhiy.storchaka
Priority: normal Keywords: easy, patch

Created on 2011-10-05 11:08 by adambyrtek, last changed 2014-01-09 21:27 by serhiy.storchaka. This issue is now closed.

Files
File name Uploaded Description Edit
fixargparse.patch elazar, 2013-09-01 21:10 patch for argparse review
argparse_ugly.patch elazar, 2013-09-11 18:42 no wrapping below width=30. +basic test review
argparse_less_ugly.patch serhiy.storchaka, 2013-09-12 21:56 review
Messages (10)
msg144947 - (view) Author: Adam Byrtek (adambyrtek) Date: 2011-10-05 11:08
Code snippet from optparse.py:

   344         self.help_position = min(max_len + 2, self.max_help_position)
   345         self.help_width = self.width - self.help_position

Where self.width is initialized with the COLUMNS environment variable. On narrow terminals it can happen that self.help_position < self.width, leading to an exception in textwrap.py:

    raise ValueError("invalid width %r (must be > 0)" % self.width)
ValueError: invalid width -15 (must be > 0)

A reasonable workaround would be to trim part of the help text instead of causing an exception.
msg145145 - (view) Author: Ezio Melotti (ezio.melotti) * (Python committer) Date: 2011-10-07 21:13
argparse has some similar code in Lib/argparse.py:489.  Can you reproduce the problem with argparse?
If you can't and argparse solved the problem already, we might adopt the same solution; if you can, it should be fixed there too.
msg196455 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-08-29 10:57
Yes, argparse has same problem.

>>> import os, argparse
>>> p = argparse.ArgumentParser(prog='PROG')
>>> os.environ['COLUMNS'] = '16'
>>> print(p.format_help())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython/Lib/argparse.py", line 2329, in format_help
    return formatter.format_help()
  File "/home/serhiy/py/cpython/Lib/argparse.py", line 276, in format_help
    help = self._root_section.format_help()
  File "/home/serhiy/py/cpython/Lib/argparse.py", line 206, in format_help
    func(*args)
  File "/home/serhiy/py/cpython/Lib/argparse.py", line 206, in format_help
    func(*args)
  File "/home/serhiy/py/cpython/Lib/argparse.py", line 514, in _format_action
    help_lines = self._split_lines(help_text, help_width)
  File "/home/serhiy/py/cpython/Lib/argparse.py", line 614, in _split_lines
    return _textwrap.wrap(text, width)
  File "/home/serhiy/py/cpython/Lib/textwrap.py", line 355, in wrap
    return w.wrap(text)
  File "/home/serhiy/py/cpython/Lib/textwrap.py", line 300, in wrap
    return self._wrap_chunks(chunks)
  File "/home/serhiy/py/cpython/Lib/textwrap.py", line 227, in _wrap_chunks
    raise ValueError("invalid width %r (must be > 0)" % self.width)
ValueError: invalid width 0 (must be > 0)
msg196740 - (view) Author: Elazar Gershuni (elazar) Date: 2013-09-01 21:10
I think in such case it is reasonable to fail silently, since the information will not be readable anyway.
Is a patch like the attached acceptable? (Sorry, I am new here)

results:

>>> import os, argparse; p = argparse.ArgumentParser(prog='PROG')
>>> os.environ['COLUMNS'] = '0'
>>> print(p.format_help())
usage: PROG
       
       [-h]

optional arguments:
  -h, --help  

>>>
msg196802 - (view) Author: Dmi Baranov (dmi.baranov) * Date: 2013-09-02 18:33
I think "ugly look is better than silence" here. Elazar, can you touch a optparse too (with some tests - test.support.EnvironmentVarGuard context manager will be helpful here)?
msg196804 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-09-02 20:47
> I think "ugly look is better than silence" here.

Agree. We have two possibilities:

1. Decrease an indentation. There is a lot of blank spaces below option's names.

2. Set some minimal width (10 or 20 characters) and let lines wrap out.

For better look we should use both methods.
msg197502 - (view) Author: Elazar Gershuni (elazar) Date: 2013-09-11 18:42
ok. how about argparse_ugly.patch? below some width it simply won't do any wrapping.

(I hadn't touch optparse yet)
msg197544 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-09-12 21:56
Here is less ugly patch (for argparse and optparse). Instead of prohibiting wrapping at all for small width, it limits minimal width of formatted text. It try first decrease the indent for help.
msg207795 - (view) Author: Roundup Robot (python-dev) Date: 2014-01-09 21:19
New changeset 779de7b4909b by Serhiy Storchaka in branch '2.7':
Issue #13107: argparse and optparse no longer raises an exception when output
http://hg.python.org/cpython/rev/779de7b4909b

New changeset c6c30b682e14 by Serhiy Storchaka in branch '3.3':
Issue #13107: argparse and optparse no longer raises an exception when output
http://hg.python.org/cpython/rev/c6c30b682e14

New changeset 48bcd03cd29f by Serhiy Storchaka in branch 'default':
Issue #13107: argparse and optparse no longer raises an exception when output
http://hg.python.org/cpython/rev/48bcd03cd29f
msg207797 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-01-09 21:27
Thank you Adam for your report. Thank you Elazar for your patch.
History
Date User Action Args
2014-02-17 11:31:19serhiy.storchakalinkissue13720 superseder
2014-01-09 21:27:18serhiy.storchakasetstatus: open -> closed
messages: + msg207797

assignee: serhiy.storchaka
resolution: fixed
stage: patch review -> resolved
2014-01-09 21:19:16python-devsetnosy: + python-dev
messages: + msg207795
2013-09-12 21:56:41serhiy.storchakasetfiles: + argparse_less_ugly.patch

messages: + msg197544
stage: test needed -> patch review
2013-09-11 18:42:17elazarsetfiles: + argparse_ugly.patch

messages: + msg197502
2013-09-02 20:47:41serhiy.storchakasetmessages: + msg196804
2013-09-02 18:33:01dmi.baranovsetnosy: + dmi.baranov
messages: + msg196802
2013-09-01 21:10:53elazarsetfiles: + fixargparse.patch

nosy: + elazar
messages: + msg196740

keywords: + patch
2013-08-29 10:57:16serhiy.storchakasetassignee: serhiy.storchaka -> (no value)
messages: + msg196455
versions: + Python 2.7, Python 3.3, Python 3.4
2013-08-26 09:17:40serhiy.storchakasetassignee: serhiy.storchaka

nosy: + serhiy.storchaka
2013-08-17 14:08:52ezio.melottisetkeywords: + easy
stage: needs patch -> test needed
2011-10-09 23:07:36ezio.melottisetnosy: + bethard, aronacher
2011-10-07 21:13:20ezio.melottisetnosy: + ezio.melotti

messages: + msg145145
stage: needs patch
2011-10-05 11:08:22adambyrtekcreate