Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use different method for propagating ctx.obj #207

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 31 additions & 17 deletions click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,10 @@ def __init__(self, command, parent=None, info_name=None, obj=None,
self.params = {}
#: the leftover arguments.
self.args = []
#: subcontexts whose objects need to be updated.
self.subcontexts = []
if obj is None and parent is not None:
obj = parent.obj
parent.subcontexts.append(self)
#: the user object stored.
self.obj = obj
#: A dictionary (-like object) with defaults for parameters.
Expand Down Expand Up @@ -239,6 +241,18 @@ def __init__(self, command, parent=None, info_name=None, obj=None,
self._close_callbacks = []
self._depth = 0

_obj = None

def _get_obj(self):
return self._obj
def _set_obj(self, obj):
self._obj = obj
for ctx in self.subcontexts:
if ctx.obj is None:
ctx.obj = obj
obj = property(_get_obj, _set_obj)
del _get_obj, _set_obj

def __enter__(self):
self._depth += 1
return self
Expand Down Expand Up @@ -925,33 +939,33 @@ def _process_result(value):
# single command but we also inform the current context about the
# name of the command to invoke.
if not self.chain:
sub_ctx = self.handle_subcommand(ctx, args)
ctx.invoked_subcommands = [sub_ctx.info_name]

# Make sure the context is entered so we do not clean up
# resources until the result processor has worked.
with ctx:
Command.invoke(self, ctx)
sub_ctx = self.handle_subcommand(ctx, args)
ctx.invoked_subcommands = [sub_ctx.info_name]
with sub_ctx:
return _process_result(sub_ctx.command.invoke(sub_ctx))

# Otherwise we make every single context and invoke them in a
# chain. In that case the return value to the result processor
# is the list of all invoked subcommand's results.
contexts = []
while args:
sub_ctx = self.handle_subcommand(ctx, args, allow_extra_args=True,
allow_interspersed_args=False)
contexts.append(sub_ctx)
args = sub_ctx.args

# Now that we have all contexts, we can invoke them.
ctx.invoked_subcommands = [x.info_name for x in contexts]

# Make sure the context is entered so we do not clean up
# resources until the result processor has worked.
with ctx:
Command.invoke(self, ctx)

# Otherwise we make every single context and invoke them in a
# chain. In that case the return value to the result processor
# is the list of all invoked subcommand's results.
contexts = []
while args:
sub_ctx = self.handle_subcommand(ctx, args, allow_extra_args=True,
allow_interspersed_args=False)
contexts.append(sub_ctx)
args = sub_ctx.args

# Now that we have all contexts, we can invoke them.
ctx.invoked_subcommands = [x.info_name for x in contexts]

rv = []
for sub_ctx in contexts:
with sub_ctx:
Expand Down
23 changes: 23 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,26 @@ def other_cmd(ctx, foo):
result = runner.invoke(cli, [])
assert not result.exception
assert result.output == '42\n'


def test_invoked_subcommand(runner):
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
if ctx.invoked_subcommand is None:
click.echo('no subcommand, use default')
ctx.invoke(sync)
else:
click.echo('invoke subcommand')

@cli.command()
def sync():
click.echo('in subcommand')

result = runner.invoke(cli, ['sync'])
assert not result.exception
assert result.output == 'invoke subcommand\nin subcommand\n'

result = runner.invoke(cli)
assert not result.exception
assert result.output == 'no subcommand, use default\nin subcommand\n'