summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Ronacher <armin.ronacher@active-4.com>2015-11-24 10:33:51 +0100
committerArmin Ronacher <armin.ronacher@active-4.com>2015-11-24 10:33:51 +0100
commit1c7e1d3f41c1d4d79a3fc0d3559f619ecc560388 (patch)
tree09f1e26e4110b590b37c75762c5f6efdadf69893
parent07a4f18863de6dee39fd491276649661f03d6347 (diff)
downloadclick-1c7e1d3f41c1d4d79a3fc0d3559f619ecc560388.tar.gz
Disallow arguments in chain mode and no longer expose leftover args.
-rw-r--r--CHANGES4
-rw-r--r--click/core.py11
-rw-r--r--tests/test_chain.py43
3 files changed, 57 insertions, 1 deletions
diff --git a/CHANGES b/CHANGES
index a138957..196af80 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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