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

Add a registry class #105

Open
lordmauve opened this issue Feb 21, 2022 · 4 comments
Open

Add a registry class #105

lordmauve opened this issue Feb 21, 2022 · 4 comments

Comments

@lordmauve
Copy link

I really like the fact that defopt works without mandatory decorators.

But, practically, I find myself repeatedly writing some small utility that allows using decorators to register subcommands to pass into defopt.run(). My most recent one looks like this:

main = CLI(short={}, parsers=...)

@main.cmd('open')
def open_(target: str, *paths: str):
    ...
    
@main.cmd
def close(target: str):
    ...
    
if __name__ == '__main__':
    main()

The decorator serves as an annotation about which functions are exposed as CLI subcommands, which is handy in a longer file where many of the functions are not exposed.

I think an optional registration utility like this would be a handy thing for defopt to have.

@anntzer
Copy link
Owner

anntzer commented Feb 21, 2022

This seems reasonable modulo API bikeshedding, but I will not have the bandwidth to consider all the options at least for the coming month(s). But I'll keep this open for later.

@anntzer
Copy link
Owner

anntzer commented Mar 12, 2022

One question, though, is how you propose to handle subcommands in this API. Perhaps foo = main.add_subcommand("foo") and then an @foo.cmd decorator? (perhaps that would be better named @foo.add_command, for consistency?)

@lordmauve
Copy link
Author

Using that pattern in Click and argparse, I find those then become a maze of indirection through a module. One alternative would be to avoid creating the intermediate objects with partially bound state and just allow the decorators to accept the path where a function will be exposed:

@main.command('project', 'new')
def new_project():
    print("creating new project")
$ myproj project new
creating new project

@anntzer
Copy link
Owner

anntzer commented Apr 7, 2022

Agreed that @main.command("foo", "bar") is likely the most user-friendly.

Do you want to try your hand at proposing a PR? :-)

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