diff --git a/Lib/argparse.py b/Lib/argparse.py index 2fb1da59f..9be18488a 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -392,6 +392,9 @@ class HelpFormatter(object): group_actions = set() inserts = {} for group in groups: + if not group._group_actions: + raise ValueError(f'empty group {group}') + try: start = actions.index(group._group_actions[0]) except ValueError: @@ -526,12 +529,13 @@ class HelpFormatter(object): parts = [action_header] # if there was help for the action, add lines of help text - if action.help: + if action.help and action.help.strip(): help_text = self._expand_help(action) - help_lines = self._split_lines(help_text, help_width) - parts.append('%*s%s\n' % (indent_first, '', help_lines[0])) - for line in help_lines[1:]: - parts.append('%*s%s\n' % (help_position, '', line)) + if help_text: + help_lines = self._split_lines(help_text, help_width) + parts.append('%*s%s\n' % (indent_first, '', help_lines[0])) + for line in help_lines[1:]: + parts.append('%*s%s\n' % (help_position, '', line)) # or add a newline if the description doesn't end with one elif not action_header.endswith('\n'): @@ -722,11 +726,13 @@ def _get_action_name(argument): if argument is None: return None elif argument.option_strings: - return '/'.join(argument.option_strings) + return '/'.join(argument.option_strings) elif argument.metavar not in (None, SUPPRESS): return argument.metavar elif argument.dest not in (None, SUPPRESS): return argument.dest + elif argument.choices: + return '{' + ','.join(argument.choices) + '}' else: return None @@ -842,6 +848,7 @@ class Action(_AttributeHolder): 'default', 'type', 'choices', + 'required', 'help', 'metavar', ] @@ -872,8 +879,8 @@ class BooleanOptionalAction(Action): option_string = '--no-' + option_string[2:] _option_strings.append(option_string) - if help is not None and default is not None: - help += f" (default: {default})" + if help is not None and default is not None and default is not SUPPRESS: + help += " (default: %(default)s)" super().__init__( option_strings=_option_strings, @@ -1250,9 +1257,9 @@ class FileType(object): # the special argument "-" means sys.std{in,out} if string == '-': if 'r' in self._mode: - return _sys.stdin - elif 'w' in self._mode: - return _sys.stdout + return _sys.stdin.buffer if 'b' in self._mode else _sys.stdin + elif any(c in self._mode for c in 'wax'): + return _sys.stdout.buffer if 'b' in self._mode else _sys.stdout else: msg = _('argument "-" with mode %r') % self._mode raise ValueError(msg) @@ -1666,7 +1673,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): """Object for parsing command line strings into Python objects. Keyword Arguments: - - prog -- The name of the program (default: sys.argv[0]) + - prog -- The name of the program (default: + ``os.path.basename(sys.argv[0])``) - usage -- A usage message (default: auto-generated from arguments) - description -- A description of what the program does - epilog -- Text following the argument descriptions @@ -1719,7 +1727,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): add_group = self.add_argument_group self._positionals = add_group(_('positional arguments')) - self._optionals = add_group(_('optional arguments')) + self._optionals = add_group(_('options')) self._subparsers = None # register types