-
Notifications
You must be signed in to change notification settings - Fork 218
Generate docs for generic easyblocks (REVIEW) #1317
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
Changes from 14 commits
0dceb5d
8fbc168
7cfc6a2
31587c9
94425d2
34c2853
e96df9a
05bd752
c657025
cc8da01
09a9742
60f70a2
0299605
5baa702
1e35b42
09c21da
d05cd30
5062e0a
c9cf03e
bf49369
fc8557e
e9b0ff1
d452321
41d8468
de8b822
7a36365
16a08db
9204337
8a4ec13
a48c80b
b48bf8c
307ae84
a75787b
cb4bd0f
3c394ae
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 |
|---|---|---|
|
|
@@ -34,25 +34,27 @@ | |
| @author: Ward Poelmans (Ghent University) | ||
| """ | ||
| import copy | ||
| import inspect | ||
| import os | ||
|
|
||
| from easybuild.framework.easyconfig.default import DEFAULT_CONFIG, HIDDEN, sorted_categories | ||
| from easybuild.framework.easyconfig.easyconfig import get_easyblock_class | ||
| from easybuild.tools.ordereddict import OrderedDict | ||
| from easybuild.tools.utilities import quote_str | ||
|
|
||
| from easybuild.tools.utilities import quote_str, import_available_modules | ||
| from easybuild.tools.filetools import read_file | ||
|
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. sort alphabetically with other |
||
|
|
||
|
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. two blank lines here please |
||
| FORMAT_RST = 'rst' | ||
| FORMAT_TXT = 'txt' | ||
|
|
||
| def det_col_width(entries, title): | ||
|
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. keep two blank lines between imports, constants, and top-level functions (so add one above here) |
||
| """Determine column width based on column title and list of entries.""" | ||
| return max(map(len, entries + [title])) | ||
|
|
||
|
|
||
| def avail_easyconfig_params_rst(title, grouped_params): | ||
| """ | ||
| Compose overview of available easyconfig parameters, in RST format. | ||
| """ | ||
| def det_col_width(entries, title): | ||
| """Determine column width based on column title and list of entries.""" | ||
| return max(map(len, entries + [title])) | ||
|
|
||
| # main title | ||
| lines = [ | ||
| title, | ||
|
|
@@ -65,29 +67,14 @@ def det_col_width(entries, title): | |
| lines.append("%s parameters" % grpname) | ||
| lines.extend(['-' * len(lines[-1]), '']) | ||
|
|
||
| name_title = "**Parameter name**" | ||
| descr_title = "**Description**" | ||
| dflt_title = "**Default value**" | ||
|
|
||
| # figure out column widths | ||
| nw = det_col_width(grouped_params[grpname].keys(), name_title) + 4 # +4 for raw format ("``foo``") | ||
| dw = det_col_width([x[0] for x in grouped_params[grpname].values()], descr_title) | ||
| dfw = det_col_width([str(quote_str(x[1])) for x in grouped_params[grpname].values()], dflt_title) | ||
|
|
||
| # 3 columns (name, description, default value), left-aligned, {c} is fill char | ||
| line_tmpl = "{0:{c}<%s} {1:{c}<%s} {2:{c}<%s}" % (nw, dw, dfw) | ||
| table_line = line_tmpl.format('', '', '', c='=', nw=nw, dw=dw, dfw=dfw) | ||
|
|
||
| # table header | ||
| lines.append(table_line) | ||
| lines.append(line_tmpl.format(name_title, descr_title, dflt_title, c=' ')) | ||
| lines.append(line_tmpl.format('', '', '', c='-')) | ||
| titles = ["**Parameter name**", "**Description**", "**Default value**"] | ||
| values = [ | ||
| ['``' + name + '``' for name in grouped_params[grpname].keys()], | ||
|
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. add comment at the end of this line: |
||
| [x[0] for x in grouped_params[grpname].values()], | ||
| [str(quote_str(x[1])) for x in grouped_params[grpname].values()] | ||
| ] | ||
|
|
||
| # table rows by parameter | ||
| for name, (descr, dflt) in sorted(grouped_params[grpname].items()): | ||
| rawname = '``%s``' % name | ||
| lines.append(line_tmpl.format(rawname, descr, str(quote_str(dflt)), c=' ')) | ||
| lines.append(table_line) | ||
| lines.extend(mk_rst_table(titles, values)) | ||
| lines.append('') | ||
|
|
||
| return '\n'.join(lines) | ||
|
|
@@ -160,3 +147,134 @@ def avail_easyconfig_params(easyblock, output_format): | |
| FORMAT_TXT: avail_easyconfig_params_txt, | ||
| } | ||
| return avail_easyconfig_params_functions[output_format](title, grouped_params) | ||
|
|
||
|
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. two blank lines between top-level functions |
||
| def generic_easyblocks(path_to_examples, common_params={}, doc_functions=[]): | ||
|
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. rename function name to make it clear this yields something in rst format |
||
| """ | ||
| Compose overview of all generic easyblocks | ||
|
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. mention rst |
||
| """ | ||
| modules = import_available_modules('easybuild.easyblocks.generic') | ||
|
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. the package name maybe rename function to
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. or, maybe just add a |
||
| docs = [] | ||
| all_blocks = [] | ||
|
|
||
| # get all blocks | ||
| for m in modules: | ||
|
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. no single-letter variable names outside of list comprehensions, use |
||
| for name,obj in inspect.getmembers(m, inspect.isclass): | ||
| eb_class = getattr(m, name) | ||
| # skip imported classes that are not easyblocks | ||
| if eb_class.__module__.startswith('easybuild.easyblocks.generic') and eb_class not in all_blocks: | ||
| all_blocks.append(eb_class) | ||
|
|
||
| for eb_class in all_blocks: | ||
|
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. sort |
||
| docs.append(doc_easyblock(eb_class, path_to_examples, common_params, doc_functions, all_blocks)) | ||
|
|
||
| toc = ['.. contents:: Available generic easyblocks', ' :depth: 1', ''] | ||
|
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. drop the |
||
|
|
||
| return toc + sorted(docs) | ||
|
|
||
|
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. insert extra blank line |
||
| def doc_easyblock(eb_class, path_to_examples, common_params, doc_functions, all_blocks): | ||
|
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. rename to |
||
| """ | ||
| Compose overview of one easyblock given class object of the easyblock in rst format | ||
|
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. mention rst |
||
| """ | ||
| classname = eb_class.__name__ | ||
|
|
||
| lines = [ | ||
| '``' + classname + '``', | ||
| '=' * (len(classname)+4), | ||
| '', | ||
| ] | ||
|
|
||
| bases = [] | ||
| for b in eb_class.__bases__: | ||
| base = b.__name__ + '_' if b in all_blocks else b.__name__ | ||
|
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. make these references to other sections, via: |
||
| bases.append(base) | ||
|
|
||
| derived = '(derives from ' + ', '.join(bases) + ')' | ||
| lines.extend([derived, '']) | ||
|
|
||
| # Description (docstring) | ||
| lines.extend([eb_class.__doc__.strip(), '']) | ||
|
|
||
| # Add extra options, if any | ||
| if eb_class.extra_options(): | ||
| extra_parameters = 'Extra easyconfig parameters specific to ``' + classname + '`` easyblock' | ||
| lines.extend([extra_parameters, '-' * len(extra_parameters), '']) | ||
| ex_opt = eb_class.extra_options() | ||
|
|
||
| titles = ['easyconfig parameter', 'description', 'default value'] | ||
| values = [ | ||
| ['``' + key + '``' for key in ex_opt], | ||
| [val[1] for val in ex_opt.values()], | ||
| ['``' + str(quote_str(val[0])) + '``' for val in ex_opt.values()] | ||
| ] | ||
|
|
||
| lines.extend(mk_rst_table(titles, values)) | ||
|
|
||
| # Add commonly used parameters | ||
| if classname in common_params: | ||
| commonly_used = 'Commonly used easyconfig parameters with ``' + classname + '`` easyblock' | ||
| lines.extend([commonly_used, '-' * len(commonly_used)]) | ||
|
|
||
| for opt in common_params[classname]: | ||
|
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. use |
||
| param = '* ``' + opt + '`` - ' + DEFAULT_CONFIG[opt][1] | ||
| lines.append(param) | ||
| lines.append('') | ||
|
|
||
| # Add docstring for custom steps | ||
| custom = [] | ||
| inh = '' | ||
| for func in doc_functions: | ||
| if func in eb_class.__dict__: | ||
| f = eb_class.__dict__[func] | ||
| elif func in eb_class.__bases__[0].__dict__: | ||
| f = eb_class.__bases__[0].__dict__[func] | ||
| inh = ' (inherited)' | ||
|
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. hmm, not sure about this, my preference would be to not included these inherited methods and only mention the ones custom to the easyblock being documented in this section |
||
|
|
||
| if f.__doc__: | ||
| custom.append('* ``' + func + '`` - ' + f.__doc__.strip() + inh) | ||
|
|
||
| if custom: | ||
| title = 'Customised steps' | ||
|
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. add |
||
| lines.extend([title, '-' * len(title)] + custom) | ||
| lines.append('') | ||
|
|
||
| # Add example if available | ||
| if classname + '.eb' in os.listdir(os.path.join(path_to_examples)): | ||
|
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. use |
||
| lines.extend(['', 'Example', '-' * 8, '', '::', '']) | ||
|
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. make section title
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. and don't hardcode |
||
| for line in read_file(os.path.join(path_to_examples, classname+'.eb')).split('\n'): | ||
|
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. what if no example is available? this will make it crash hard, it should just skip the
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. we maybe only include examples for some easyblocks, especially with non-generic ones
Contributor
Author
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. With
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. ah, yes, missed that |
||
| lines.append(' ' + line.strip()) | ||
| lines.append('') # empty line after literal block | ||
|
|
||
| return '\n'.join(lines) | ||
|
|
||
| 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) | ||
| table = [] | ||
| col_widths = [] | ||
| tmpl = [] | ||
| line= [] | ||
|
|
||
| # figure out column widths | ||
| for i in range(0, num_col): | ||
| col_widths.append(det_col_width(values[i], titles[i])) | ||
|
|
||
| # make line template | ||
| tmpl.append('{' + str(i) + ':{c}<' + str(col_widths[i]) + '}') | ||
| line.append('') # needed for table line | ||
|
|
||
| line_tmpl = ' '.join(tmpl) | ||
| 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])): | ||
| table.append(line_tmpl.format(*[v[i] for v in values], c=' ')) | ||
|
|
||
| table.extend([table_line, '']) | ||
|
|
||
| return table | ||
|
|
||
|
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. drop emtpy line |
||
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.
sort imported functions alphabetically