diff options
author | Amy <leiamy12@gmail.com> | 2020-07-01 13:33:59 -0400 |
---|---|---|
committer | David Lord <davidism@gmail.com> | 2020-10-12 17:46:05 -0700 |
commit | d314f45b8e9e59e0e82604868de41624ec8d13ed (patch) | |
tree | 6ced204f1362181a18893ae2786801d77895d125 /src/click/parser.py | |
parent | 7332f00ed4c27d8da041788ca6a7aa405f062c76 (diff) | |
download | click-d314f45b8e9e59e0e82604868de41624ec8d13ed.tar.gz |
add ability to provide non-flag option without value
use flag_value or prompt if an option is given without a value
Diffstat (limited to 'src/click/parser.py')
-rw-r--r-- | src/click/parser.py | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/src/click/parser.py b/src/click/parser.py index f613947..92c9354 100644 --- a/src/click/parser.py +++ b/src/click/parser.py @@ -29,6 +29,11 @@ from .exceptions import BadOptionUsage from .exceptions import NoSuchOption from .exceptions import UsageError +# Sentinel value that indicates an option was passed as a flag without a +# value but is not a flag option. Option.consume_value uses this to +# prompt or use the flag_value. +_flag_needs_value = object() + def _unpack_args(args, nargs_spec): """Given an iterable of arguments and an iterable of nargs specifications, @@ -81,12 +86,6 @@ def _unpack_args(args, nargs_spec): return tuple(rv), list(args) -def _error_opt_args(nargs, opt): - if nargs == 1: - raise BadOptionUsage(opt, f"{opt} option requires an argument") - raise BadOptionUsage(opt, f"{opt} option requires {nargs} arguments") - - def split_opt(opt): first = opt[:1] if first.isalnum(): @@ -343,14 +342,7 @@ class OptionParser: if explicit_value is not None: state.rargs.insert(0, explicit_value) - nargs = option.nargs - if len(state.rargs) < nargs: - _error_opt_args(nargs, opt) - elif nargs == 1: - value = state.rargs.pop(0) - else: - value = tuple(state.rargs[:nargs]) - del state.rargs[:nargs] + value = self._get_value_from_state(opt, option, state) elif explicit_value is not None: raise BadOptionUsage(opt, f"{opt} option does not take a value") @@ -383,14 +375,7 @@ class OptionParser: state.rargs.insert(0, arg[i:]) stop = True - nargs = option.nargs - if len(state.rargs) < nargs: - _error_opt_args(nargs, opt) - elif nargs == 1: - value = state.rargs.pop(0) - else: - value = tuple(state.rargs[:nargs]) - del state.rargs[:nargs] + value = self._get_value_from_state(opt, option, state) else: value = None @@ -407,6 +392,38 @@ class OptionParser: if self.ignore_unknown_options and unknown_options: state.largs.append(f"{prefix}{''.join(unknown_options)}") + def _get_value_from_state(self, option_name, option, state): + nargs = option.nargs + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = _flag_needs_value + else: + n_str = "an argument" if nargs == 1 else f"{nargs} arguments" + raise BadOptionUsage( + option_name, f"{option_name} option requires {n_str}." + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = _flag_needs_value + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + def _process_opts(self, arg, state): explicit_value = None # Long option handling happens in two parts. The first part is |