-
Notifications
You must be signed in to change notification settings - Fork 124
Help categories #348
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
Help categories #348
Conversation
Added example of multiple commands grouped by categories
Reads the __doc__ for a command function and provides the first block of text for each command. Updated help_categories.py to demonstrate a multi-line comment block for a command.
cmd2.py
Outdated
| widest = 0 | ||
| # measure the commands | ||
| for command in cmds: | ||
| width = wcswidth(command) |
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.
You need to put this in a conditional check since wcswidth() is not available on Windows. You would so something like the following:
if 'gnureadline' in sys.modules or 'readline' in sys.modules:
width = wcswidth(command)
else:
width = len(command)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.
It turns out we don't allow arbitrary unicode characters in the command names so I can actually just remove this.
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.
That is an even better solution.
tleonhardt
left a comment
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.
Need to fix the issue where wcswidth isn't available on Windows.
| @@ -0,0 +1,138 @@ | |||
| #!/usr/bin/env python | |||
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.
The example is nice and helps explain to end users how to use it.
A couple unit tests covering the new features added would be extremely beneficial from a maintenance perspective.
|
Thanks for the PR @anselor! Please fix the dependency issue on Windows. A few unit tests covering the new features would be greatly appreciated if you don't mind taking the time to add them. |
|
If you update the Sphinx docs a little to mention the new features, you get bonus points ;-) |
|
I will need to tweak complete_help() since it isn't expecting a flag. |
|
@anselor @tleonhardt I do think we need to change what displays in verbose for some commands. |
Codecov Report
@@ Coverage Diff @@
## master #348 +/- ##
=========================================
+ Coverage 89.23% 89.64% +0.4%
=========================================
Files 1 1
Lines 1932 2008 +76
=========================================
+ Hits 1724 1800 +76
Misses 208 208
Continue to review full report at Codecov.
|
|
@tleonhardt I don't see anything in the current Sphinx docs covering how to document your commands. |
…and> function provided. In verbose help, added check for argparse usage block (starting with 'usage: '), to skip that block and move to the next comment block Added unit tests for new categorization code Updated example to demonstrate skipping of argparse usage statement
|
Wow, we really don't. The closest we have is this paragraph in the Argument Processing section. Feel free to add something earlier ;-) I think the initial thought was we didn't want to duplicate documentation for features which were implemented and documented within cmd. But now our support for help has grown beyond the base |
| edit history py quit shell unalias | ||
| """ | ||
|
|
||
| BASE_HELP_VERBOSE = """ |
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.
Thanks for adding the unit tests. They should really help with maintainability.
tleonhardt
left a comment
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 is looking pretty good. Thanks for the fixes and updates.
tleonhardt
left a comment
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.
The test_base_argparse_help unit test is now failing on Python 2.7.
Fix that and then this PR should hopefully be good to go minus potential documentation updates.
…egory. Changed the detection of with_argparse decorated commands to be less hacky/brittle. Now it tags the function with help_summary. Fixed issue with handling commands that provide a custom help_ function. We can now redirect the output to a string to be formatted with the other commands. Added some documentation explaining the new help categories. Updated unit tests.
|
@tleonhardt I'm looking forward to retiring Python 2 support. The gymnastics to keep it working are annoying. |
|
@anselor Yeah, I now wish that @kotfu and I had agreed on an earlier date for ending Python 2 support than August 31, 2018. The burden of supporting Python 2.7 is getting worse by the month. Tell you what, if you can convince @kotfu that moving the date earlier (perhaps May 31, 2018 or even April 30, 2018) is desirable then I am happy to buy-in to that decision. I know moving it earlier would make @kmvanbrunt very happy. |
| else: | ||
| from contextlib import redirect_stdout, redirect_stderr | ||
|
|
||
| if sys.version_info > (3, 0): |
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.
FYI, using the six module can help avoid Python 2 vs 3 compatibility gymnastics such as this.
six is a Python 2 vs 3 compatibility module (6 == 2 * 3 == 3 * 2).
| return lexed_arglist | ||
|
|
||
|
|
||
| def with_category(category): |
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.
I like that you added a decorator, that should make the code clean and easy to read.
I strongly encourage you to make one simple change to your decorator to help avoid order-of-operations dependencies when multiple decorators are involved.
You should apply the "@functools.wraps(func)" decorator to your internal cat_decorator function - see how we do it in other decorators below such as with_argument_list:
def with_category(category):
"""A decorator to apply a category to a command function"""
@functools.wraps(func)
def cat_decorator(func):
categorize(func, category)
return func
return cat_decoratorThere 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.
I don't think that's necessary in this situation because this decorator function is truly a decorator function rather than a wrapping function. This adds an attribute the the passed-in function and returns it.
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.
You make a good point, your decorator is mutating and returning the original function. I think you are fine as-is.
tleonhardt
left a comment
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.
Use functools.wraps in your new decorator to avoid decorator order of application mattering when multiple deorators are used on a function.
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.
I think this is good to go.
Every now and then the AppVeyor Windows CI tool just gets stuck for no good reason. Can you please push some trivial change to force it to run? Maybe updated the CHANGELOG or something?
Adds ability to optionally group commands into categories:

As well as a way to see more verbose help output:

help -v / help --verbose
This addresses #278