0

Say I have a function created not by def but by a partial() call (or even just by assignment). In the example below, how can I add bar as a click sub-command to the cli group? I can't use the decorator approach (as with foo). My failed approaches are shown below in-line.

import functools
import click


@click.group()
def cli():
    pass


@cli.command()
def foo(myname="foo"):
    print(f"I am {myname}")


bar = functools.partial(foo, myname="bar")

# this has no effect
# cli.command(bar)

# results in: AttributeError: 'functools.partial' object has no attribute 'name'
# cli.add_command(bar)

# results in: AttributeError: 'functools.partial' object has no attribute 'hidden'
# cli.add_command(bar, name="bar")

if __name__ == "__main__":
    cli()


UPDATE: Actually, it looks like the partial is the culprit here. This answer in a different but related thread, points out that partial objects are "missing certain attributes, specifically __module__ and __name__".

Owen
  • 3,063
  • 5
  • 30
  • 26

1 Answers1

1

I think you're missing the fact that the @command decorator turns the foo function into a Command that uses the original foo as callback. The original function is still accessible as foo.callback but foo is a Command. Still, you can't use a partial object as callback because it lacks __name__, but you can work around that passing the name explicitly:

bar = functools.partial(foo.callback, myname="bar")
cli.command("bar")(bar)

# Alternative:
cli.add_command(click.Command("bar", callback=bar))
janluke
  • 1,567
  • 1
  • 15
  • 19