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

Using plugin alias that doesn't match click.group method name #17

Closed
grovduck opened this issue Jan 10, 2018 · 2 comments
Closed

Using plugin alias that doesn't match click.group method name #17

grovduck opened this issue Jan 10, 2018 · 2 comments

Comments

@grovduck
Copy link

(Sorry that this is probably a bit more of a help question than an issue, but it didn't look like there was much activity on SO for click-plugins ...)

I'm trying to register a click group as both a console script and a click plugin. Assuming my CLI code for the plugin looks like this:

import click

@click.group()
def main_group():
    """
    Root plugin group
    """

@main_group.command(
    'subcommand_1',
    short_help='Subcommand #1'
)
def subcommand_1():
    print('This is subcommand #1')

and the entry_points section of setup.py looks like this:

entry_points='''
    [console_scripts]
    foo=root_plugin.cli:main_group
        
    [root.plugins]
    plugin=root_plugin.cli:main_group
'''

When I run the main root console script, I get this:

Usage: root [OPTIONS] COMMAND [ARGS]...

  Root command line interface

Options:
  --version  Show the version and exit.
  --help     Show this message and exit.

Commands:
  main_group  Root plugin group

I was expecting that main_group would have been called plugin instead based on the entry point. Note that using the foo console script works as expected. In the examples I've seen, the plugin alias always matches the click group name, e.g. here, but is it possible to give it a different alias?

@geowurster
Copy link
Member

@grovduck questions are welcome! The docs definitely need some work.

This is a use case I had not considered but after poking around the behavior is, surprisingly, correct. You're on the right track with your point about entry point names matching the objects they reference. The string plugin=root_plugin.cli:main_group is a set of instructions for pkg_resources. plugin is an ID you are assigning to root_plugin.cli:main_group, which points to a Python object. In code terms:

from pkg_resources import iter_entry_points

mapping = {e.name: e.load() for e in iter_entry_points('root.plugins')}

which produces:

{'plugin': <click.core.Group at 0x10b379668>}

click then uses the Group()'s name as the subcommand name in the CLI:

mapping['plugin'].name

which defaults to the function name, which in this case is main_group.

The solution is to do @click.group(name='plugin-name') so you can reference $ root plugin-name.

Alternatively, click derives a default Group.name from the decorated function's name, so you could change the name of main_group() to plugin(). The $ foo command is correct because you're telling setuptools to install an executable called foo pointing to main_group. For the top Group() in the chain click uses the executable's name rather than Group.name. You can see this behavior by adding this snippet to your root_plugin/cli.py file and executing directly:

if __name__ == '__main__':
    main_group()

Although the displayed program name can also be changed in this case with main_group(prog_name='foo').

Caveat: if an exception is encountered in EntryPoint.load() the plugin will be registered under EntryPoint.name rather than Group.name. Executing $ root plugin will reveal the traceback.

  plugin     † Warning: could not load plugin. See `root plugin --help`.

I'll leave this ticket open and add this info to the docs.

@grovduck
Copy link
Author

Excellent, thanks so much @geowurster. I hadn't seen that syntax on click.group() before. Works like a charm.

@grovduck grovduck closed this as completed Apr 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants