Make each subparser get a crack all all arguments.
This commit is contained in:
parent
8c72e909a7
commit
881dc9b01e
1 changed files with 25 additions and 67 deletions
|
@ -37,61 +37,41 @@ SUBPARSER_ALIASES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def split_arguments_by_subparser(arguments, subparsers):
|
def parse_subparser_arguments(arguments, top_level_parser, subparsers):
|
||||||
'''
|
'''
|
||||||
Parse out the arguments destined for each subparser. Also parse out global arguments not
|
Given a sequence of arguments, a top-level parser (containing subparsers), and a subparsers
|
||||||
destined for a particular subparser.
|
object as returned by argparse.ArgumentParser().add_subparsers(), ask each subparser to parse
|
||||||
|
its own arguments and the top-level parser to parse any remaining arguments.
|
||||||
More specifically, given a sequence of arguments and a subparsers object as returned by
|
|
||||||
argparse.ArgumentParser().add_subparsers(), split the arguments on subparser names. Return the
|
|
||||||
result as a dict mapping from subparser name to the arguments for that subparser. This includes
|
|
||||||
a special subparser named "global" for global arguments.
|
|
||||||
'''
|
|
||||||
subparser_arguments = collections.defaultdict(list)
|
|
||||||
subparser_name = 'global'
|
|
||||||
|
|
||||||
for argument in arguments:
|
|
||||||
subparser = subparsers.choices.get(argument)
|
|
||||||
|
|
||||||
if subparser is None:
|
|
||||||
subparser_arguments[subparser_name].append(argument)
|
|
||||||
else:
|
|
||||||
subparser_name = argument
|
|
||||||
subparser_arguments[subparser_name] = []
|
|
||||||
|
|
||||||
return subparser_arguments
|
|
||||||
|
|
||||||
|
|
||||||
def parse_subparser_arguments(subparser_arguments, top_level_parser, subparsers):
|
|
||||||
'''
|
|
||||||
Given a dict mapping from subparser name to the arguments for that subparser, a top-level parser
|
|
||||||
(containing subparsers), and a subparsers object as returned by
|
|
||||||
argparse.ArgumentParser().add_subparsers(), ask each subparser to parse its own arguments and
|
|
||||||
the top-level parser to parse any remaining arguments.
|
|
||||||
|
|
||||||
Return the result as a dict mapping from subparser name (or "global") to a parsed namespace of
|
Return the result as a dict mapping from subparser name (or "global") to a parsed namespace of
|
||||||
arguments.
|
arguments.
|
||||||
'''
|
'''
|
||||||
parsed_arguments = collections.OrderedDict()
|
parsed_arguments = collections.OrderedDict()
|
||||||
global_arguments = subparser_arguments['global']
|
remaining_arguments = list(arguments)
|
||||||
alias_to_subparser_name = {
|
alias_to_subparser_name = {
|
||||||
alias: subparser_name
|
alias: subparser_name
|
||||||
for subparser_name, aliases in SUBPARSER_ALIASES.items()
|
for subparser_name, aliases in SUBPARSER_ALIASES.items()
|
||||||
for alias in aliases
|
for alias in aliases
|
||||||
}
|
}
|
||||||
|
|
||||||
for subparser_name, arguments in subparser_arguments.items():
|
# Give each subparser a shot at parsing all arguments.
|
||||||
if subparser_name == 'global':
|
for subparser_name, subparser in subparsers.choices.items():
|
||||||
|
if subparser_name not in arguments:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
remaining_arguments.remove(subparser_name)
|
||||||
canonical_name = alias_to_subparser_name.get(subparser_name, subparser_name)
|
canonical_name = alias_to_subparser_name.get(subparser_name, subparser_name)
|
||||||
subparser = subparsers.choices.get(canonical_name)
|
|
||||||
|
|
||||||
parsed, remaining = subparser.parse_known_args(arguments)
|
parsed, remaining = subparser.parse_known_args(arguments)
|
||||||
parsed_arguments[canonical_name] = parsed
|
parsed_arguments[canonical_name] = parsed
|
||||||
global_arguments.extend(remaining)
|
|
||||||
|
|
||||||
parsed_arguments['global'] = top_level_parser.parse_args(global_arguments)
|
# Then ask each subparser, one by one, to greedily consume arguments. Any arguments that remain
|
||||||
|
# are global arguments.
|
||||||
|
for subparser_name in parsed_arguments.keys():
|
||||||
|
subparser = subparsers.choices[subparser_name]
|
||||||
|
parsed, remaining_arguments = subparser.parse_known_args(remaining_arguments)
|
||||||
|
|
||||||
|
parsed_arguments['global'] = top_level_parser.parse_args(remaining_arguments)
|
||||||
|
|
||||||
return parsed_arguments
|
return parsed_arguments
|
||||||
|
|
||||||
|
@ -99,7 +79,7 @@ def parse_subparser_arguments(subparser_arguments, top_level_parser, subparsers)
|
||||||
def parse_arguments(*arguments):
|
def parse_arguments(*arguments):
|
||||||
'''
|
'''
|
||||||
Given command-line arguments with which this script was invoked, parse the arguments and return
|
Given command-line arguments with which this script was invoked, parse the arguments and return
|
||||||
them as an argparse.ArgumentParser instance.
|
them as a dict mapping from subparser name (or "global") to an argparse.Namespace instance.
|
||||||
'''
|
'''
|
||||||
config_paths = collect.get_default_config_paths()
|
config_paths = collect.get_default_config_paths()
|
||||||
|
|
||||||
|
@ -317,8 +297,7 @@ def parse_arguments(*arguments):
|
||||||
'-h', '--help', action='help', help='Show this help message and exit'
|
'-h', '--help', action='help', help='Show this help message and exit'
|
||||||
)
|
)
|
||||||
|
|
||||||
subparser_arguments = split_arguments_by_subparser(arguments, subparsers)
|
parsed_arguments = parse_subparser_arguments(arguments, top_level_parser, subparsers)
|
||||||
parsed_arguments = parse_subparser_arguments(subparser_arguments, top_level_parser, subparsers)
|
|
||||||
|
|
||||||
if parsed_arguments.excludes_filename:
|
if parsed_arguments.excludes_filename:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -328,40 +307,19 @@ def parse_arguments(*arguments):
|
||||||
if 'init' in parsed_arguments and parsed_arguments['global'].dry_run:
|
if 'init' in parsed_arguments and parsed_arguments['global'].dry_run:
|
||||||
raise ValueError('The init action cannot be used with the --dry-run option')
|
raise ValueError('The init action cannot be used with the --dry-run option')
|
||||||
|
|
||||||
if args.progress and not (args.create or args.extract):
|
if 'list' in parsed_arguments and 'info' in parsed_arguments and parged_arguments['list'].json and parged_arguments['info'].json:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'The --progress option can only be used with the --create and --extract options'
|
'With the --json option, list and info actions cannot be used together'
|
||||||
)
|
|
||||||
|
|
||||||
if args.json and not (args.create or args.list or args.info):
|
|
||||||
raise ValueError(
|
|
||||||
'The --json option can only be used with the --create, --list, or --info options'
|
|
||||||
)
|
|
||||||
|
|
||||||
if args.json and args.list and args.info:
|
|
||||||
raise ValueError(
|
|
||||||
'With the --json option, options --list and --info cannot be used together'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# If any of the action flags are explicitly requested, leave them as-is. Otherwise, assume
|
# If any of the action flags are explicitly requested, leave them as-is. Otherwise, assume
|
||||||
# defaults: Mutate the given arguments to enable the default actions.
|
# defaults: Mutate the given arguments to enable the default actions.
|
||||||
if (
|
if set(parsed_arguments) == {'global'}:
|
||||||
not args.init
|
parsed_arguments['prune'] = prune_parser.parse_known_args(arguments)
|
||||||
and not args.prune
|
parsed_arguments['create'] = create_parser.parse_known_args(arguments)
|
||||||
and not args.create
|
parsed_arguments['check'] = check_parser.parse_known_args(arguments)
|
||||||
and not args.check
|
|
||||||
and not args.extract
|
|
||||||
and not args.list
|
|
||||||
and not args.info
|
|
||||||
):
|
|
||||||
args.prune = True
|
|
||||||
args.create = True
|
|
||||||
args.check = True
|
|
||||||
|
|
||||||
if args.stats and not (args.create or args.prune):
|
return parsed_arguments
|
||||||
raise ValueError('The --stats option can only be used when creating or pruning archives')
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def run_configuration(config_filename, config, args): # pragma: no cover
|
def run_configuration(config_filename, config, args): # pragma: no cover
|
||||||
|
|
Loading…
Reference in a new issue