-
Notifications
You must be signed in to change notification settings - Fork 38
Introduce class CommandArgumentParser [RHELDST-34542] #278
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
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,118 @@ | ||||
| import argparse | ||||
| import sys | ||||
|
|
||||
| from kobo.plugins import Plugin | ||||
|
|
||||
|
|
||||
| class ArgparseCommand(Plugin): | ||||
| """ | ||||
| Base class for argparse-based commands. | ||||
|
|
||||
| Commands must: | ||||
| - inherit from ArgparseCommand | ||||
| - implement add_arguments(self) | ||||
| - implement run(self, *args, **kwargs) | ||||
| """ | ||||
|
|
||||
| def __init__(self, parser): | ||||
| Plugin.__init__(self) | ||||
| self.parser = parser | ||||
|
|
||||
| def add_arguments(self): | ||||
| """Register argparse arguments.""" | ||||
| raise NotImplementedError | ||||
|
|
||||
| def run(self, *args, **kwargs): | ||||
| """Execute command.""" | ||||
| raise NotImplementedError | ||||
|
|
||||
|
|
||||
| class CommandArgumentParser(object): | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be equivalent Line 153 in eec6a3d
but it doesn't seem to provide everything, do you intend to implement the rest? |
||||
| """ | ||||
| Argparse-based command dispatcher. | ||||
|
|
||||
| This intentionally does NOT inherit from argparse.ArgumentParser. | ||||
| It is a coordinator that: | ||||
| - parses the global command name | ||||
| - dispatches to an argparse-capable command | ||||
| """ | ||||
|
|
||||
| def __init__( | ||||
| self, | ||||
| command_container, | ||||
| prog=None, | ||||
| default_command=None, | ||||
| default_profile=None, | ||||
| ): | ||||
| self.container = command_container | ||||
| self.default_command = default_command | ||||
| self.default_profile = default_profile | ||||
|
|
||||
| self.parser = argparse.ArgumentParser( | ||||
| prog=prog, | ||||
| usage="%(prog)s <command> [args] [--help]", | ||||
| formatter_class=argparse.RawTextHelpFormatter, | ||||
| ) | ||||
|
|
||||
| self.parser.add_argument( | ||||
| "command", | ||||
| nargs="?", | ||||
| help="command to execute", | ||||
| ) | ||||
|
|
||||
| # everything after the command name | ||||
| self.parser.add_argument( | ||||
| "args", | ||||
| nargs=argparse.REMAINDER, | ||||
| help=argparse.SUPPRESS, | ||||
| ) | ||||
|
|
||||
| def _load_profile(self, profile): | ||||
| """ | ||||
| Hook for loading a profile. | ||||
| Implemented here only as a placeholder. | ||||
| """ | ||||
| pass | ||||
|
|
||||
| def run(self, argv=None): | ||||
| cmd, cmd_ns, cmd_args = self.parse_args(argv) | ||||
|
|
||||
| cmd_kwargs = vars(cmd_ns) | ||||
|
|
||||
| # load profile if requested | ||||
| if self.default_profile and "profile" in cmd_kwargs: | ||||
| self._load_profile(cmd_kwargs["profile"]) | ||||
|
|
||||
| return cmd.run(*cmd_args, **cmd_kwargs) | ||||
|
|
||||
| def parse_args(self, argv=None): | ||||
| argv = argv if argv is not None else sys.argv[1:] | ||||
| ns = self.parser.parse_args(argv) | ||||
|
|
||||
| command_name = ns.command or self.default_command | ||||
|
|
||||
| if not command_name: | ||||
| self.parser.error("no command specified") | ||||
|
|
||||
| if command_name not in self.container.plugins: | ||||
| self.parser.error("unknown command: %s" % command_name) | ||||
|
|
||||
| CommandClass = self.container[command_name] | ||||
|
|
||||
| if not issubclass(CommandClass, ArgparseCommand): | ||||
| self.parser.error("command '%s' does not support argparse" % command_name) | ||||
|
|
||||
| cmd_parser = argparse.ArgumentParser( | ||||
| prog="%s %s" % (self.parser.prog, command_name), | ||||
| formatter_class=argparse.RawTextHelpFormatter, | ||||
| ) | ||||
|
|
||||
| cmd_parser.container = self.container | ||||
|
|
||||
| cmd = CommandClass(cmd_parser) | ||||
| cmd.add_arguments() | ||||
|
|
||||
| # allow extra args (optparse compatibility) | ||||
| cmd_ns, remainder = cmd_parser.parse_known_args(ns.args) | ||||
|
|
||||
| return cmd, cmd_ns, remainder | ||||
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from kobo.argcli import ArgparseCommand | ||
|
|
||
| __all__ = ("Cmd_Fake_Echo",) | ||
|
|
||
|
|
||
| class Cmd_Fake_Echo(ArgparseCommand): | ||
| enabled = True | ||
| name = "fake-echo" | ||
|
|
||
| def add_arguments(self): | ||
| self.parser.add_argument("words", nargs="+") | ||
|
|
||
| def run(self, *args, **kwargs): | ||
| # store result on container | ||
| self.parser.container.result = kwargs["words"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import kobo.client | ||
| from kobo.argcli import CommandArgumentParser | ||
| from tests.plugins import commands | ||
|
|
||
|
|
||
| class FakeCommandContainer(kobo.client.ClientCommandContainer): | ||
| pass | ||
|
|
||
|
|
||
| FakeCommandContainer.register_module(commands, prefix="cmd_") | ||
|
|
||
|
|
||
| class FakeCommandArgumentParser(CommandArgumentParser): | ||
| def load_pub_profile(self, profile=None): | ||
| pass | ||
|
|
||
|
|
||
| def test_argparse_command_registered_via_module(): | ||
| conf = kobo.conf.PyConfigParser() | ||
| container = FakeCommandContainer(conf) | ||
|
|
||
| parser = FakeCommandArgumentParser( | ||
| command_container=container, | ||
| default_profile="default-profile", | ||
| ) | ||
|
|
||
| parser.run(["cmd-fake-echo", "hello", "world"]) | ||
|
|
||
| assert container.result == ["hello", "world"] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be equivalent of
kobo/kobo/cli.py
Line 153 in eec6a3d
but there some attributes that you didn't add here. How do you intend to support them?