diff options
author | Armin Ronacher <armin.ronacher@active-4.com> | 2015-11-24 10:33:51 +0100 |
---|---|---|
committer | Armin Ronacher <armin.ronacher@active-4.com> | 2015-11-24 10:33:51 +0100 |
commit | 1c7e1d3f41c1d4d79a3fc0d3559f619ecc560388 (patch) | |
tree | 09f1e26e4110b590b37c75762c5f6efdadf69893 | |
parent | 07a4f18863de6dee39fd491276649661f03d6347 (diff) | |
download | click-1c7e1d3f41c1d4d79a3fc0d3559f619ecc560388.tar.gz |
Disallow arguments in chain mode and no longer expose leftover args.
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | click/core.py | 11 | ||||
-rw-r--r-- | tests/test_chain.py | 43 |
3 files changed, 57 insertions, 1 deletions
@@ -36,6 +36,10 @@ Version 6.0 - Unittests now always force a certain virtual terminal width. - Added support for allowing dashes to indicate standard streams to the `Path` type. +- Multi commands in chain mode no longer propagate arguments left over + from parsing to the callbacks. It's also now disallowed through an + exception that arguments are attached to multi commands if chain mode + is enabled. Version 5.1 ----------- diff --git a/click/core.py b/click/core.py index f7cbfc2..a580e42 100644 --- a/click/core.py +++ b/click/core.py @@ -927,6 +927,12 @@ class MultiCommand(Command): #: overridden with the :func:`resultcallback` decorator. self.result_callback = result_callback + if self.chain: + for param in self.params: + if isinstance(param, Argument): + raise RuntimeError('Multi commands in chain mode cannot ' + 'have other arguments.') + def collect_usage_pieces(self, ctx): rv = Command.collect_usage_pieces(self, ctx) rv.append(self.subcommand_metavar) @@ -1041,6 +1047,9 @@ class MultiCommand(Command): # set to ``*`` to inform the command that subcommands are executed # but nothing else. with ctx: + # The master command does not receive any arguments. That + # would be silly. + ctx.args = [] ctx.invoked_subcommand = args and '*' or None Command.invoke(self, ctx) @@ -1054,7 +1063,7 @@ class MultiCommand(Command): allow_extra_args=True, allow_interspersed_args=False) contexts.append(sub_ctx) - args = sub_ctx.args + args, sub_ctx.args = sub_ctx.args, [] rv = [] for sub_ctx in contexts: diff --git a/tests/test_chain.py b/tests/test_chain.py index 9f86a8f..aee6f2d 100644 --- a/tests/test_chain.py +++ b/tests/test_chain.py @@ -1,4 +1,6 @@ +import sys import click +import pytest def test_basic_chaining(runner): @@ -152,3 +154,44 @@ def test_pipeline(runner): 'FOO', 'BAR', ] + + +def test_args_and_chain(runner): + def debug(): + click.echo('%s=%s' % ( + sys._getframe(1).f_code.co_name, + '|'.join(click.get_current_context().args), + )) + + @click.group(chain=True) + def cli(): + debug() + + @cli.command() + def a(): + debug() + + @cli.command() + def b(): + debug() + + @cli.command() + def c(): + debug() + + result = runner.invoke(cli, ['a', 'b', 'c']) + assert not result.exception + assert result.output.splitlines() == [ + 'cli=', + 'a=', + 'b=', + 'c=', + ] + + +def test_multicommand_no_args(runner): + with pytest.raises(RuntimeError): + @click.group(chain=True) + @click.argument('forbidden') + def cli(): + pass |