You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Adding group to CommandCollection loses group options #347
lots of commands that require and use a config file.
init command that creates a valid config file.
Attempt
importosimportclick@click.group()defcli_noconfig():
# need this because you can't add Commands to a CommandCollection, only MultiCommandspass@cli_noconfig.command("init")@click.option("--config", type=click.Path(exists=False), default=os.path.join(click.get_app_dir('foo', force_posix=True), "foo.conf"))definit(config):
# creates the config fileprint"init! creating config: %s"%config@click.group()@click.option("--config", type=click.File('r'), default=os.path.join(click.get_app_dir('foo', force_posix=True), "foo.conf"))@click.pass_contextdefcli_main(ctx, config):
print"main! config=%s"%configctx.obj['config'] =config@cli_main.command('cmd1')@click.pass_contextdefcmd1(ctx):
print"cmd1! config=%s"%ctx.obj.get('config')
# ... lots more commands that use & require the config file# promote both groups to the "top" levelcli=click.CommandCollection(sources=[cli_noconfig, cli_main])
if__name__=='__main__':
cli(obj={})
Problem
The file parameter (and any other parameters/options on the cli_main group) get dropped/ignored when the commands are accessed via the CommandCollection.
Not sure if this is a bug (it's certainly unobvious), and I'm curious as to what other approaches could solve my problem? Looks like I can't override a group parameter for a specific command either, right? And validation callbacks don't appear to get passed context or anything else I can use to figure out which command is being run...
the two referenced issues don't help with the above situation where the options are on one of the command groups being specified in the collection. For example:
I don't know if I'm rationalizing but to me this is actually expected behaviour: you are taking commands from one or more groups, and making the cli group pretend that they are in its group, thus the original groups are no longer in the picture... so why would their options still be used? You could say that the options should be used but that would mean the original groups are still present which is not the case I think, as it would imply each command of the original groups are getting a second parent.
Is it not possible to put those options on the command collection itself? If not, or if not all groups added to the command collection use the special options, you could also just refactor the group option code into your own decorator like @config_option, and command that has this decorator will support that option.
Reacted by Oleh Prypin, BNMetrics, Alexandr Chichenin, Thomas Gamauf, zheladev and nickpetrovic
I'm a little unclear on the exact use case that this bug pertains to. I think @scholli has some good recommendations for anyone hitting this issue. Also a similar issue with a workaround #1179 .
Was this previously possible in click at some point?
I have found a workaround for this, you will need to extend click.CommandCollection, like so:
class CommandGroupCollection(click.CommandCollection):
@property
def sources_map(self) -> dict:
"""
A dictionary representation of {command_name: source_group_object}
"""
r = {}
for source in self.sources:
if not isinstance(source, click.Group):
continue
for command in source.commands:
r[command] = source
return r
def invoke(self, ctx):
if ctx.protected_args:
group = self.sources_map.get(ctx.protected_args[0])
if group:
group.invoke(ctx)
else:
super().invoke(ctx)
Reacted by Sviatoslav Bogachev, Keiran Raine, Andrii Oriekhov and nickpetrovic
I hit this issue today. Mentally, click.CommandCollection seems like it merges groups of commands. It's surprising that the callback of each group is lost in this process. This is with click 7.1.2.
In my case, the purpose is to merge built-in commands with custom subcommands (similar to git). All the built-in commands need the same setup.
Activity
rcoup commentedon Jun 8, 2015
cluelessperson commentedon Oct 4, 2016
Same here, completely broken.
Now I have to spell it out in every, single, command.
the above code ONLY outputs "test"
howdydoody123 commentedon Jan 25, 2017
ziazon commentedon Apr 2, 2019
the two referenced issues don't help with the above situation where the options are on one of the command groups being specified in the collection. For example:
Doesn't work.
Neither does doing
cli = click.CommandCollection(sources=[with_profile, without_profile])schollii commentedon May 7, 2019
I don't know if I'm rationalizing but to me this is actually expected behaviour: you are taking commands from one or more groups, and making the cli group pretend that they are in its group, thus the original groups are no longer in the picture... so why would their options still be used? You could say that the options should be used but that would mean the original groups are still present which is not the case I think, as it would imply each command of the original groups are getting a second parent.
Is it not possible to put those options on the command collection itself? If not, or if not all groups added to the command collection use the special options, you could also just refactor the group option code into your own decorator like
@config_option, and command that has this decorator will support that option.jcrotts commentedon May 7, 2019
I'm a little unclear on the exact use case that this bug pertains to. I think @scholli has some good recommendations for anyone hitting this issue. Also a similar issue with a workaround #1179 .
Was this previously possible in click at some point?
BNMetrics commentedon Jul 15, 2019
I have found a workaround for this, you will need to extend
click.CommandCollection, like so:shmolyneaux commentedon Mar 2, 2021
I hit this issue today. Mentally,
click.CommandCollectionseems like it merges groups of commands. It's surprising that the callback of each group is lost in this process. This is with click 7.1.2.In my case, the purpose is to merge built-in commands with custom subcommands (similar to git). All the built-in commands need the same setup.
Rowlando13 commentedon Dec 29, 2024
This issue is ready to be documented or closed now that changes to command collection have been merged.
Rowlando13 commentedon Sep 23, 2025
Going to close since command collection is deprecated.