-
Notifications
You must be signed in to change notification settings - Fork 51
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
Added output format options for --help #180
Changes from 2 commits
c907b67
061649b
5ec0d20
799b0d7
3bcb2bb
e601d57
2b9b9ec
9869871
11d5841
e164783
47f856a
8a13d7d
774667e
2671948
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# # | ||
# Copyright 2015-2015 Ghent University | ||
# | ||
# This file is part of vsc-base, | ||
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), | ||
# with support of Ghent University (http://ugent.be/hpc), | ||
# the Flemish Supercomputer Centre (VSC) (https://vscentrum.be/nl/en), | ||
# the Hercules foundation (http://www.herculesstichting.be/in_English) | ||
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). | ||
# | ||
# http://github.com/hpcugent/vsc-base | ||
# | ||
# vsc-base is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Library General Public License as | ||
# published by the Free Software Foundation, either version 2 of | ||
# the License, or (at your option) any later version. | ||
# | ||
# vsc-base is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Library General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Library General Public License | ||
# along with vsc-base. If not, see <http://www.gnu.org/licenses/>. | ||
# # | ||
""" | ||
A class that has some support functions for generating rst documentation | ||
|
||
@author: Caroline De Brouwer (Ghent University) | ||
""" | ||
|
||
def det_col_width(entries, title): | ||
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. not sure if this still makes sense, since it's only used in one place anymore? |
||
"""Determine column width based on column title and list of entries.""" | ||
return max(map(len, entries + [title])) | ||
|
||
def mk_rst_table(titles, values): | ||
""" | ||
Returns an rst table with given titles and values (a nested list of string values for each column) | ||
""" | ||
num_col = len(titles) | ||
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. move it up and use it in the comparison |
||
table = [] | ||
col_widths = [] | ||
tmpl = [] | ||
line= [] | ||
|
||
# figure out column widths | ||
for i in range(0, num_col): | ||
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. use for i, title i enumerate(titles): |
||
col_widths.append(det_col_width(values[i], titles[i])) | ||
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. is 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. maybe collapse them together into one variable named |
||
|
||
# make line template | ||
tmpl.append('{' + str(i) + ':{c}<' + str(col_widths[i]) + '}') | ||
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. string templating, not 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. if the 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. or use |
||
line.append('') # needed for table line | ||
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. so at the end of this loop, line = [''] * num_col |
||
|
||
line_tmpl = ' '.join(tmpl) | ||
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. make clear how many space the 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. +1, introduce something like |
||
table_line = line_tmpl.format(*line, c="=") | ||
|
||
table.append(table_line) | ||
table.append(line_tmpl.format(*titles, c=' ')) | ||
table.append(table_line) | ||
|
||
for i in range(0, len(values[0])): | ||
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.
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. ok, no 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. transpose with map(list, zip(*A)) |
||
table.append(line_tmpl.format(*[v[i] for v in values], c=' ')) | ||
|
||
table.extend([table_line, '']) | ||
|
||
return table |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
# | ||
# | ||
# # | ||
# Copyright 2011-2014 Ghent University | ||
# | ||
# This file is part of vsc-base, | ||
|
@@ -46,6 +45,7 @@ | |
from optparse import SUPPRESS_HELP as nohelp # supported in optparse of python v2.4 | ||
from optparse import _ as _gettext # this is gettext normally | ||
from vsc.utils.dateandtime import date_parser, datetime_parser | ||
from vsc.utils.docs import mk_rst_table | ||
from vsc.utils.fancylogger import getLogger, setLogLevel, getDetailsLogLevels | ||
from vsc.utils.missing import shell_quote, nub | ||
from vsc.utils.optcomplete import autocomplete, CompleterOption | ||
|
@@ -162,9 +162,9 @@ class ExtOption(CompleterOption): | |
DISABLE = 'disable' # inverse action | ||
|
||
EXTOPTION_EXTRA_OPTIONS = ('date', 'datetime', 'regex', 'add', 'add_first', 'add_flex',) | ||
EXTOPTION_STORE_OR = ('store_or_None',) # callback type | ||
EXTOPTION_STORE_OR = ('store_or_None', 'formathelp') # callback type | ||
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. rename all 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. and/or this (not sure)? EXTOPTION_STORE_OR = ('store_or_None', ) + EXTOPTION_HELP |
||
EXTOPTION_LOG = ('store_debuglog', 'store_infolog', 'store_warninglog',) | ||
EXTOPTION_HELP = ('shorthelp', 'confighelp',) | ||
EXTOPTION_HELP = ('shorthelp', 'confighelp', 'help') | ||
|
||
ACTIONS = Option.ACTIONS + EXTOPTION_EXTRA_OPTIONS + EXTOPTION_STORE_OR + EXTOPTION_LOG + EXTOPTION_HELP | ||
STORE_ACTIONS = Option.STORE_ACTIONS + EXTOPTION_EXTRA_OPTIONS + EXTOPTION_LOG + ('store_or_None',) | ||
|
@@ -211,9 +211,10 @@ def store_or(option, opt_str, value, parser, *args, **kwargs): | |
self.callback = store_or | ||
self.callback_kwargs = { | ||
'orig_default': copy.deepcopy(self.default), | ||
} | ||
} | ||
self.action = 'callback' # act as callback | ||
if self.store_or == 'store_or_None': | ||
|
||
if self.store_or in ('store_or_None', 'formathelp'): | ||
self.default = None | ||
else: | ||
self.log.raiseException("_set_attrs: unknown store_or %s" % self.store_or, exception=ValueError) | ||
|
@@ -222,7 +223,13 @@ def take_action(self, action, dest, opt, value, values, parser): | |
"""Extended take_action""" | ||
orig_action = action # keep copy | ||
|
||
if action == 'shorthelp': | ||
# dest is None for actions like shorthelp and confighelp | ||
if dest and getattr(parser._long_opt.get('--'+dest, ''), 'store_or', '') == 'formathelp': | ||
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. magic string |
||
Option.take_action(self, action, dest, opt, value, values, parser) | ||
fn = getattr(parser, 'print_%shelp' % values.help) | ||
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. needs a default or check that the method/attribute exists 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. checking can be done with 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. needs a default like fn = getattr(parser, 'print_%shelp' % values.help, None)
if fn is None:
... some error
else:
fn()
parser.exit() 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. @Caylo: you forgot the |
||
fn() | ||
parser.exit() | ||
elif action == 'shorthelp': | ||
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. open an issue to convert 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. see #181 |
||
parser.print_shorthelp() | ||
parser.exit() | ||
elif action == 'confighelp': | ||
|
@@ -567,8 +574,7 @@ def print_shorthelp(self, fh=None): | |
|
||
self.print_help(fh) | ||
|
||
def print_help(self, fh=None): | ||
"""Intercept print to file to print to string and remove the ENABLE/DISABLE options from help""" | ||
def check_help(self, fh): | ||
if self.help_to_string: | ||
self.help_to_file = StringIO.StringIO() | ||
if fh is None: | ||
|
@@ -583,9 +589,63 @@ def _is_enable_disable(x): | |
for opt in self._get_all_options(): | ||
# remove all long_opts with ENABLE/DISABLE naming | ||
opt._long_opts = [x for x in opt._long_opts if not _is_enable_disable(x)] | ||
return fh | ||
|
||
def print_help(self, fh=None): | ||
"""Intercept print to file to print to string and remove the ENABLE/DISABLE options from help""" | ||
fh = self.check_help(fh) | ||
OptionParser.print_help(self, fh) | ||
|
||
def print_rsthelp(self, fh=None): | ||
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. just drop the 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. nvm |
||
""" Print help in rst format """ | ||
fh = self.check_help(fh) | ||
result = [] | ||
title = "Easybuild help" | ||
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. nope, has nothing to do with EB 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. so make this an argument to this method, maybe with some sensible default |
||
result.extend([title, "=" * len(title)]) | ||
if self.usage: | ||
result.append("Usage: ``%s``" % self.get_usage().replace("Usage: ", '').strip()) | ||
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. dedicated |
||
result.append('') | ||
if self.description: | ||
result.append(self.description) | ||
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. description section? |
||
result.append('') | ||
|
||
result.append(self.format_option_rsthelp()) | ||
|
||
print "\n".join(result) | ||
|
||
def format_option_rsthelp(self, formatter=None): | ||
""" Formatting for help in rst format """ | ||
if not formatter: | ||
formatter = self.formatter | ||
formatter.store_option_strings(self) | ||
|
||
res = [] | ||
opt_title = "Options" | ||
res.extend([opt_title, '-' * len(opt_title)]) | ||
titles = ["Option", "Help"] | ||
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. replace with titles = ["Option flag", "Option description"] |
||
values = [[],[]] | ||
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. build the regular matrix, pass the transpose to |
||
for opt in self.option_list: | ||
if not opt.help is nohelp: | ||
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. why wouldn't the help be a valid documented option? 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.
|
||
values[0].append('``%s``' % formatter.option_strings[opt]) | ||
values[1].append(formatter.expand_default(opt)) | ||
|
||
res.extend(mk_rst_table(titles, values)) | ||
res.append('') | ||
|
||
for group in self.option_groups: | ||
res.extend([group.title, '-' * len(group.title)]) | ||
values[0] = [] | ||
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.
|
||
values[1] = [] | ||
for opt in group.option_list: | ||
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 looks the same as above, make an (internal) function for it |
||
if not opt.help is nohelp: | ||
values[0].append('``%s``' % formatter.option_strings[opt]) | ||
values[1].append(formatter.expand_default(opt)) | ||
|
||
res.extend(mk_rst_table(titles, values)) | ||
res.append('') | ||
|
||
return '\n'.join(res) | ||
|
||
def print_confighelp(self, fh=None): | ||
"""Print help as a configfile.""" | ||
|
||
|
@@ -633,7 +693,8 @@ def _add_help_option(self): | |
help=_gettext("show short help message and exit")) | ||
self.add_option("-%s" % self.longhelp[0], | ||
self.longhelp[1], # *self.longhelp[1:], syntax error in Python 2.4 | ||
action="help", | ||
action="formathelp", | ||
default='', | ||
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 also needs a 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 needed to become a 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. add a choice with possible suppoted help formats 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.
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. add this: metavar='OUTPUT_FORMAT', |
||
help=_gettext("show full help message and exit")) | ||
self.add_option("--confighelp", | ||
action="confighelp", | ||
|
@@ -792,6 +853,7 @@ def __init__(self, **kwargs): | |
'usage': kwargs.get('usage', self.USAGE), | ||
'version': self.VERSION, | ||
}) | ||
|
||
self.parser = self.PARSER(**kwargs) | ||
self.parser.allow_interspersed_args = self.INTERSPERSED | ||
|
||
|
@@ -1423,6 +1485,8 @@ def generate_cmd_line(self, ignore=None, add_default=None): | |
opt_dests.sort() | ||
|
||
for opt_dest in opt_dests: | ||
# help is store_or_None, but is not a processed option, so skip it | ||
if opt_dest in ExtOption.EXTOPTION_HELP: continue | ||
opt_value = self.options.__dict__[opt_dest] | ||
# this is the action as parsed by the class, not the actual action set in option | ||
# (eg action store_or_None is shown here as store_or_None, not as callback) | ||
|
@@ -1453,7 +1517,7 @@ def generate_cmd_line(self, ignore=None, add_default=None): | |
(opt_name, opt_value)) | ||
continue | ||
|
||
if action in ('store_or_None',): | ||
if action in ('store_or_None', 'formathelp'): | ||
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. use |
||
if opt_value == default: | ||
self.log.debug("generate_cmd_line %s adding %s (value is default value %s)" % | ||
(action, opt_name, opt_value)) | ||
|
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 not a class, just remove the whole
A class that has some support
part