diff -r 9ea84f006892 Lib/argparse.py
--- a/Lib/argparse.py Wed May 01 15:15:50 2013 +0200
+++ b/Lib/argparse.py Tue Jul 16 11:49:43 2013 -0700
@@ -311,21 +311,15 @@
# build full usage string
format = self._format_actions_usage
- action_usage = format(optionals + positionals, groups)
- usage = ' '.join([s for s in [prog, action_usage] if s])
+ action_parts = format(optionals + positionals, groups)
+ usage = ' '.join([prog]+action_parts)
# wrap the usage parts if it's too long
text_width = self._width - self._current_indent
if len(prefix) + len(usage) > text_width:
- # break usage into wrappable parts
- part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
- opt_usage = format(optionals, groups)
- 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
+ opt_parts = format(optionals, groups)
+ pos_parts = format(positionals, groups)
# helper for wrapping lines
def get_lines(parts, indent, prefix=None):
@@ -336,7 +330,7 @@
else:
line_len = len(indent) - 1
for part in parts:
- if line_len + 1 + len(part) > text_width:
+ if line and line_len + 1 + len(part) > text_width:
lines.append(indent + ' '.join(line))
line = []
line_len = len(indent) - 1
@@ -377,61 +371,75 @@
return '%s%s\n\n' % (prefix, usage)
def _format_actions_usage(self, actions, groups):
- # find group indices and identify actions in groups
- group_actions = set()
- inserts = {}
- for group in groups:
- try:
- start = actions.index(group._group_actions[0])
- except ValueError:
- continue
- else:
- end = start + len(group._group_actions)
- if actions[start:end] == group._group_actions:
- for action in group._group_actions:
- group_actions.add(action)
- if not group.required:
- if start in inserts:
- inserts[start] += ' ['
- else:
- inserts[start] = '['
- inserts[end] = ']'
- else:
- if start in inserts:
- inserts[start] += ' ('
- else:
- inserts[start] = '('
- inserts[end] = ')'
- for i in range(start + 1, end):
- inserts[i] = '|'
+ # format the usage using the actions list. Where possible
+ # format the groups that include those actions
+ # The actions list has priority
+ # This is a new version that formats the groups directly without
+ # needing inserts, (most) cleanup, or parsing into parts
+ parts = []
+ i = 0
+ # step through the actions list
+ while i1:
+ parts[-1] = ')' if group.required else ']'
+ else:
+ # nothing added
+ parts = []
+ arg_parts = [''.join(parts)]
+
+ def cleanup(text):
+ # remove unnecessary ()
+ text = _re.sub(r'^\(([^|]*)\)$', r'\1', text)
+ return text
+ arg_parts = [cleanup(t) for t in arg_parts]
+ return arg_parts
+
+ def _format_just_actions_usage(self, actions):
+ # actions, without any group markings
+ parts = []
+ for action in actions:
if action.help is SUPPRESS:
- parts.append(None)
- if inserts.get(i) == '|':
- inserts.pop(i)
- elif inserts.get(i + 1) == '|':
- inserts.pop(i + 1)
-
- # produce all arg strings
+ pass
elif not action.option_strings:
default = self._get_default_metavar_for_positional(action)
part = self._format_args(action, default)
-
- # if it's in a group, strip the outer []
- if action in group_actions:
- if part[0] == '[' and part[-1] == ']':
- part = part[1:-1]
-
- # add the action string to the list
parts.append(part)
-
- # produce the first way to invoke the option in brackets
else:
option_string = action.option_strings[0]
@@ -447,31 +455,11 @@
args_string = self._format_args(action, default)
part = '%s %s' % (option_string, args_string)
- # make it look optional if it's not required or in a group
- if not action.required and action not in group_actions:
+ # make it look optional if it's not required
+ if not action.required:
part = '[%s]' % part
-
- # add the action string to the list
parts.append(part)
-
- # insert things at the necessary indices
- for i in sorted(inserts, reverse=True):
- parts[i:i] = [inserts[i]]
-
- # join all the action items with spaces
- text = ' '.join([item for item in parts if item is not None])
-
- # clean up separators for mutually exclusive groups
- open = r'[\[(]'
- close = r'[\])]'
- text = _re.sub(r'(%s) ' % open, r'\1', text)
- text = _re.sub(r' (%s)' % close, r'\1', text)
- text = _re.sub(r'%s *%s' % (open, close), r'', text)
- text = _re.sub(r'\(([^|]*)\)', r'\1', text)
- text = text.strip()
-
- # return the text
- return text
+ return parts
def _format_text(self, text):
if '%(prog)' in text:
diff -r 9ea84f006892 Lib/test/test_argparse.py
--- a/Lib/test/test_argparse.py Wed May 01 15:15:50 2013 +0200
+++ b/Lib/test/test_argparse.py Tue Jul 16 11:49:43 2013 -0700
@@ -4118,6 +4118,46 @@
version = ''
+class TestHelpMetavarArgumentsInnerBracketSplitLines(HelpTestCase):
+ """"""
+
+ def custom_type(string):
+ return string
+
+ parser_signature = Sig(prog='PROG')
+ long_a = 'a' * 60
+ long_d = 'd' * 60
+ argument_signatures = [Sig('--a', metavar=long_a),
+ Sig('--b', metavar='[innerpart]outerpart'),
+ Sig('--c'),
+ Sig('d', metavar=long_d),
+ Sig('e', metavar='[innerpart2]outerpart2'),
+ Sig('f'),
+ ]
+ argument_group_signatures = []
+ usage = '''\
+ usage: PROG [-h]
+ [--a {0}]
+ [--b [innerpart]outerpart] [--c C]
+ {1}
+ [innerpart2]outerpart2 f
+ '''.format(long_a, long_d)
+ help = usage + '''\
+
+ positional arguments:
+ {0}
+ [innerpart2]outerpart2
+ f
+
+ optional arguments:
+ -h, --help show this help message and exit
+ --a {1}
+ --b [innerpart]outerpart
+ --c C
+ '''.format(long_d, long_a)
+ version = ''
+
+
# =====================================
# Optional/Positional constructor tests
# =====================================