|
27 | 27 |
|
28 | 28 | import llnl.util.filesystem as fs
|
29 | 29 | import llnl.util.tty as tty
|
| 30 | +import llnl.util.tty.colify |
30 | 31 | import llnl.util.tty.color as color
|
31 | 32 | from llnl.util.tty.log import log_output
|
32 | 33 |
|
@@ -173,14 +174,16 @@ def _format_actions_usage(self, actions, groups):
|
173 | 174 | usage = super(
|
174 | 175 | SpackHelpFormatter, self)._format_actions_usage(actions, groups)
|
175 | 176 |
|
| 177 | + # Eliminate any occurrence of two or more consecutive spaces |
| 178 | + usage = re.sub(r'[ ]{2,}', ' ', usage) |
| 179 | + |
176 | 180 | # compress single-character flags that are not mutually exclusive
|
177 | 181 | # at the beginning of the usage string
|
178 | 182 | chars = ''.join(re.findall(r'\[-(.)\]', usage))
|
179 | 183 | usage = re.sub(r'\[-.\] ?', '', usage)
|
180 | 184 | if chars:
|
181 |
| - return '[-%s] %s' % (chars, usage) |
182 |
| - else: |
183 |
| - return usage |
| 185 | + usage = '[-%s] %s' % (chars, usage) |
| 186 | + return usage.strip() |
184 | 187 |
|
185 | 188 |
|
186 | 189 | class SpackArgumentParser(argparse.ArgumentParser):
|
@@ -293,7 +296,18 @@ def add_subcommand_group(title, commands):
|
293 | 296 | def add_subparsers(self, **kwargs):
|
294 | 297 | """Ensure that sensible defaults are propagated to subparsers"""
|
295 | 298 | kwargs.setdefault('metavar', 'SUBCOMMAND')
|
| 299 | + |
| 300 | + # From Python 3.7 we can require a subparser, earlier versions |
| 301 | + # of argparse will error because required=True is unknown |
| 302 | + if sys.version_info[:2] > (3, 6): |
| 303 | + kwargs.setdefault('required', True) |
| 304 | + |
296 | 305 | sp = super(SpackArgumentParser, self).add_subparsers(**kwargs)
|
| 306 | + # This monkey patching is needed for Python 3.5 and 3.6, which support |
| 307 | + # having a required subparser but don't expose the API used above |
| 308 | + if sys.version_info[:2] == (3, 5) or sys.version_info[:2] == (3, 6): |
| 309 | + sp.required = True |
| 310 | + |
297 | 311 | old_add_parser = sp.add_parser
|
298 | 312 |
|
299 | 313 | def add_parser(name, **kwargs):
|
@@ -336,6 +350,15 @@ def format_help(self, level='short'):
|
336 | 350 | # in subparsers, self.prog is, e.g., 'spack install'
|
337 | 351 | return super(SpackArgumentParser, self).format_help()
|
338 | 352 |
|
| 353 | + def _check_value(self, action, value): |
| 354 | + # converted value must be one of the choices (if specified) |
| 355 | + if action.choices is not None and value not in action.choices: |
| 356 | + cols = llnl.util.tty.colify.colified( |
| 357 | + sorted(action.choices), indent=4, tty=True |
| 358 | + ) |
| 359 | + msg = 'invalid choice: %r choose from:\n%s' % (value, cols) |
| 360 | + raise argparse.ArgumentError(action, msg) |
| 361 | + |
339 | 362 |
|
340 | 363 | def make_argument_parser(**kwargs):
|
341 | 364 | """Create an basic argument parser without any subcommands added."""
|
|
0 commit comments