Comments (14)
@kmvanbrunt
There are a wealth of existing modules which support parsing sub-commands including:
- argparse: https://docs.python.org/3/library/argparse.html
- probably by far the most common framework used for sub-commands in Python (since it is built in)
- ArgumentParser.add_subparsers
- click: http://click.pocoo.org/5/
- clean decorator-based framework
- from a developer and architecture perspective I really like the way this tool deals with nested commands:
- docopt: https://github.com/docopt/docopt
- Define the argument parsing by writing the documentation
- Powerful, but learning curve is high and syntax is finicky
- cmdln: https://github.com/trentm/cmdln
- an alternative to cmd2 which also extends cmd
- So not directly useful, but could serve as a reference
from cmd2.
Now that we are using argparse for command argument parsing, doors have been open for this. Users can manually do it using argparse. But maybe we could come up with some sort of clever deocrator-based approach akin to how click
approaches subcommands that helps make it easier?
from cmd2.
If we can't think of a good way of adding explicit support for nested commands (i.e. subcommands), then perhaps it would be sufficient to simply document by example how to use argparse to do this.
from cmd2.
Since this is possible using argparse, I'll add some documentation and an example or two showing how to do it with argparse. That can be our first step, and then we can reassess whether we should add additional support later.
from cmd2.
I've come up with a system that allows you to nest Cmd classes within each other. The top level (root) command then handles passing the subcommands down to it's subordinates. You can also "change directory" so that you are at the subcommand's level and therefore do not need to specify the subcommand anymore.
I tried to come up with a decorator like approach but found it to be too complicated. I also liked the ability to separate the subcommands into their own class, it bodes well for code organizing.
I'm not sure how this works with argparse, I don't have much experience with it.
I plan to validate my changes against the test suit today.
Edit: Tests have been completed successfully. I'm now going to focus on adding additional tests for this feature.
from cmd2.
@lobocv
Hi Calvin, it is a pleasure to make your acquaintance. Let us know when you are happy with your system that allows you to nest Cmd classes in order to support subcommands and @kotfu and I can take a look at it. We can either take a look at it within a branch on your fork or you can submit a PR. I'm curious to see what you have devised. Having separate Cmd classes for subcommands sounds really non-intuitive to me, but I promise to approach your solution with an open mind, so maybe you can make a convert of me ;-)
argparse
has rather nice support for subcommands built into it. I've used it in the past and have been very happy with it. Basically you add a "subparser" to the main parser for each subcommand. It then does a good job of contextually providing help.
from cmd2.
@tleonhardt Happy to meet you too!
I would have preferred to make a separate SubCommand class (and maybe we can still go that route). My reasoning for having separate classes for each subcommand and then layering them were:
- Code cleanliness. When a command line tool gets too large it's easier to read if the subcommands can be grouped together and placed in a separate file.
- Modularity. Subcommands can be run as the root / top level command line without any code modifications / relying on a root Cmd class.
- Easier to implement (for me at least!) since CLI functions are just redirected to a function of the same name/structure in a subordinate CLI class.
I'm not too familiar with the unit test framework being used in this project so that may take me a little while to figure out. My preliminary tests seem to work and not broken anything!
Please feel free to branch off my fork and play around. I'll add an example here shortly.
I've added a example of nesting commands in examples/subcommands.py (on my fork). Please have a look
from cmd2.
@lobocv
pytest is a wonderful unit test framework. If you haven't already checked it out our Contributor's Guide has some good suggestions for using it. In particular, I would highly recommend the xdist plugin for running tests in parallel - it really speeds things up.
Honestly, the vast majority of our tests are integration tests, not unit tests. So please don't take what we have as an example of how to write good unit tests though ;-)
from cmd2.
@lobocv
I took a look at what you are doing in your fork on the feature/subcommands branch.
As it turns out what you are doing is totally, radically different from what I have been envisioning when I have talked about a feature that adds support for subcommands.
What I'm talking about is akin to a command such as "git" where that one command has many subcommands - i.e. "git clone", "git status", "git commit", etc. If you "git -h" you will get very different help information than if you do "git clone -h". So effectively it is one command with various subcommands, where each subcommand takes different options, but all are invokable from the same prompt. Except in the context of cmd2
these would be invokable from the cmd2
interactive prompt instead of the shell's command-line.
What you have done is more akin to architecting a way to turn a cmd2
-based application into a menu-driven application by having "subcommands" which are really submenus or nested cmd2.Cmd applications.
What you have done is pretty cool and I like it, but I'm not sure I can see a clean way to merge it into the mainstream cmd2
baseline in a way that would be generically useful for and compatible with all other cmd2
applications. Perhaps with some clever work we could. What you have created is a cool feature (though not the same one as this Issue discusses), but you are doing some things which would not be acceptable for general applications, such as altering the prompt. Many cmd2
apps involve code where developers are highly tweaking the prompt, including dynamic updating based on data from background threads and such.
Even if we didn't merge it into the main baseline, maybe we could merge in an example or something. I do think it is a nice example of how to do nested cmd2
apps where you have different commands available in different states.
@kotfu and/or @kmvanbrunt if either of you have a chance to look at his code, I'd like to hear your thoughts.
from cmd2.
@tleonhardt Thanks for having a look at my work. I had a feeling that my connotation of "subcommand" was slightly different. From now on I will use "submenu" instead of "subcommand". For my job I needed the feature I had made and I thought it would be helpful to contribute it back to the project. I understand the changes are quite significant and can have an adverse affect on people if we merged it. I'm not sure what the best approach would be now.
If the changing of the prompt is a concern, perhaps we can find a solution to that. Currently I alter the prompt to show the "scope" at which the CLI resides. Perhaps, if the prompt is manually changed it, can override this feature.
The library seems to behave the same if you don't use nested Cmd's so perhaps it may not be a problem for people not using this feature.
I'd love to hear everyone's thoughts.
Edit: There may actually be a better way to do this that would not involve altering the cmd2.Cmd class. Instead we can use a decorator that can override the root level Cmd to add do_* commands which perform the redirecting into submenus. This way we shouldn't get any unintended affects by altering the core code and any problems should reside for the most part in the overriding decorator. Perhaps you will be more comfortable with that approach.
from cmd2.
@lobocv
I really like the idea of a decorator-based approach for providing the sub-menu feature instead of altering the cmd2.Cmd class itself. I think I would be pretty comfortable merging in such a feature.
from cmd2.
@lobocv
I created Issue #256 to explore adding a sub-menu feature. It would probably be a good idea to move future discussion of this feature there since it is logically a different feature than this issue was created to discuss.
from cmd2.
PR #257 contains an example of how to use argparse sub-commands as well as a tweak to cmd2
so that it properly supports help for sub-commands.
If anyone has any comments or suggestions for improvement, I'd appreciate hearing them.
from cmd2.
@lobocv Just an FYI, you can look at the subcommands.py example that recently got merged into master to see what we were talking about in terms of support for sub-commands.
from cmd2.
Related Issues (20)
- CMD2 gives Error 'width must be at least 1' When using Columnize to order a list of items with long names HOT 1
- Sumline
- updating the prompt overwrites incremental search HOT 1
- Can I call Command Scripts from python code? HOT 1
- cmd2 and a-Shell HOT 7
- Edit auto complete in a specific directory HOT 1
- poutput() and ansi styles.
- tttt HOT 1
- Adding a did you mean? or most similar command in case of error HOT 10
- Typing problem: use of @with_argparser will cause mypy to issue an error HOT 4
- New versions of Statekeeper, ParsedString HOT 3
- Generates an AttributeError when used in a pyinstaller-packaged application HOT 3
- mypy since 1.6.0 introduces validation error
- Allow class member method to be argparse factory
- comments are not stripped when a command is decorated by "cmd2.with_argparser" HOT 1
- onecmd returns False if command returns None, different from cmd module behavior
- Persistent history file not saved when application is killed HOT 2
- how to save the Settable HOT 2
- Can't run first application example HOT 1
- readline history is fragmented when using multiline commands
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cmd2.