Skip to content
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

Generate docs for generic easyblocks (REVIEW) #1317

Merged
merged 35 commits into from
Jul 15, 2015
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0dceb5d
Begin script for generic easyblock documentation
Caylo Jul 6, 2015
8fbc168
Generic easyblock docs, continued
Caylo Jul 7, 2015
7cfc6a2
python star operator is gr8
Caylo Jul 7, 2015
31587c9
Separate function for making rst tables
Caylo Jul 7, 2015
94425d2
Merge branch 'generic-easyblock-docs-issue636' of github.com:Caylo/ea…
Caylo Jul 7, 2015
34c2853
Also use mk_rst_table in avail_easyconfig_params
Caylo Jul 7, 2015
e96df9a
added table of contents
Caylo Jul 7, 2015
05bd752
Fixed some remarks
Caylo Jul 8, 2015
c657025
Delete :q
Caylo Jul 8, 2015
cc8da01
added custom step functions to doc
Caylo Jul 8, 2015
09a9742
remove examples from framework
Caylo Jul 8, 2015
60f70a2
Merge branch 'generic-easyblock-docs-issue636' of github.com:Caylo/ea…
Caylo Jul 8, 2015
0299605
added internal references for parent classes
Caylo Jul 8, 2015
5baa702
added mark for inherited functions
Caylo Jul 8, 2015
1e35b42
added page title
Caylo Jul 8, 2015
09c21da
Small fixes
Caylo Jul 8, 2015
d05cd30
More fixes
Caylo Jul 9, 2015
5062e0a
Small rst_table unit test
Caylo Jul 9, 2015
c9cf03e
fix merge
Caylo Jul 9, 2015
bf49369
remove example files
Caylo Jul 9, 2015
fc8557e
Update on doc for generic easyblocks
Caylo Jul 10, 2015
e9b0ff1
Merge branch 'develop' into generic-easyblock-docs-issue636
boegel Jul 10, 2015
d452321
Merge pull request #3 from boegel/generic-easyblock-docs-issue636
Caylo Jul 10, 2015
41d8468
Merge branch 'develop' into generic-easyblock-docs-issue636
boegel Jul 13, 2015
de8b822
Merge pull request #4 from boegel/generic-easyblock-docs-issue636
Caylo Jul 13, 2015
7a36365
sorted imports
Caylo Jul 13, 2015
16a08db
Merge branch 'generic-easyblock-docs-issue636' of github.com:Caylo/ea…
Caylo Jul 13, 2015
9204337
Fixed remarks
Caylo Jul 13, 2015
8a4ec13
sort easyblocks
Caylo Jul 13, 2015
a48c80b
remove debug print
Caylo Jul 13, 2015
b48bf8c
forgot a ':'
Caylo Jul 13, 2015
307ae84
rst documentation for generic easyblocks unit test
Caylo Jul 14, 2015
a75787b
Merge branch 'generic-easyblock-docs-issue636' of github.com:Caylo/ea…
Caylo Jul 14, 2015
cb4bd0f
table of contents as list
Caylo Jul 15, 2015
3c394ae
remark above title
Caylo Jul 15, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions easybuild/tools/doc_examples/Binary.eb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
easyblock = 'Binary'

name = 'Platanus'
version = '1.2.1'
versionsuffix = '-linux-x86_64'

homepage = 'http://platanus.bio.titech.ac.jp/'
description = """PLATform for Assembling NUcleotide Sequences"""

toolchain = {'name': 'dummy', 'version': 'dummy'}

source_urls = ['http://platanus.bio.titech.ac.jp/Platanus_release/20130901010201']
sources = ['platanus']
checksums = ['02cf92847ec704d010a54df293b9c60a']

sanity_check_paths = {
'files': ['platanus'],
'dirs': [],
}

moduleclass = 'bio'
17 changes: 17 additions & 0 deletions easybuild/tools/doc_examples/Bundle.eb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
easyblock = 'Bundle'

name = 'Autotools'
version = '20150119' # date of the most recent change

homepage = 'http://autotools.io'
description = """This bundle collect the standard GNU build tools: Autoconf, Automake and libtool"""

toolchain = {'name': 'GCC', 'version': '4.9.2'}

dependencies = [
('Autoconf', '2.69'), # 20120424
('Automake', '1.15'), # 20150105
('libtool', '2.4.5'), # 20150119
]

moduleclass = 'devel'
30 changes: 30 additions & 0 deletions easybuild/tools/doc_examples/CMakeMake.eb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
easyblock = 'CMakeMake'

name = 'ANTs'
version = '2.1.0rc3'

homepage = 'http://stnava.github.io/ANTs/'
description = """ANTs extracts information from complex datasets that include imaging. ANTs is useful for managing,
interpreting and visualizing multidimensional data."""

toolchain = {'name': 'goolf', 'version': '1.5.14'}
toolchainopts = {'pic': True}

source_urls = ['https://github.com/stnava/ANTs/archive/']
sources = ['v%(version)s.tar.gz']

builddependencies = [('CMake', '3.0.2')]

skipsteps = ['install']
buildopts = ' && mkdir -p %(installdir)s && cp -r * %(installdir)s/'

parallel = 1

separate_build_dir = True

sanity_check_paths = {
'files': ['bin/ANTS'],
'dirs': ['lib'],
}

moduleclass = 'data'
20 changes: 20 additions & 0 deletions easybuild/tools/doc_examples/ConfigureMake.eb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
easyblock = 'ConfigureMake'

name = 'zsync'
version = '0.6.2'

homepage = 'http://zsync.moria.org.uk/'
description = """zsync-0.6.2: Optimising file distribution program, a 1-to-many rsync"""

sources = [SOURCE_TAR_BZ2]
source_urls = ['http://zsync.moria.org.uk/download/']


toolchain = {'name': 'ictce', 'version': '5.3.0'}

sanity_check_paths = {
'files': ['bin/zsync'],
'dirs': []
}

moduleclass = 'tools'
33 changes: 33 additions & 0 deletions easybuild/tools/doc_examples/ConfigureMakePythonPackage.eb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
easyblock = 'ConfigureMakePythonPackage'

name = 'PyQt'
version = '4.11.3'

homepage = 'http://www.riverbankcomputing.co.uk/software/pyqt'
description = """PyQt is a set of Python v2 and v3 bindings for Digia's Qt application framework."""

toolchain = {'name': 'goolf', 'version': '1.5.14'}

sources = ['%(name)s-x11-gpl-%(version)s.tar.gz']
source_urls = ['http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-%(version)s']

python = 'Python'
pyver = '2.7.9'
pythonshortver = '.'.join(pyver.split('.')[:2])
versionsuffix = '-%s-%s' % (python, pyver)

dependencies = [
(python, pyver),
('SIP', '4.16.4', versionsuffix),
('Qt', '4.8.6'),
]

configopts = "configure-ng.py --confirm-license"
configopts += " --destdir=%%(installdir)s/lib/python%s/site-packages " % pythonshortver
configopts += " --no-sip-files"

options = {'modulename': 'PyQt4'}

modextrapaths = {'PYTHONPATH': 'lib/python%s/site-packages' % pythonshortver}

moduleclass = 'vis'
155 changes: 127 additions & 28 deletions easybuild/tools/docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort imported functions alphabetically

from easybuild.tools.filetools import read_file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sort alphabetically with other from ... import lines


Copy link
Member

Choose a reason for hiding this comment

The 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):
Copy link
Member

Choose a reason for hiding this comment

The 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,
Expand All @@ -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 = [
[backtick(name) for name in grouped_params[grpname].keys()],
[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)
Expand Down Expand Up @@ -160,3 +147,115 @@ def avail_easyconfig_params(easyblock, output_format):
FORMAT_TXT: avail_easyconfig_params_txt,
}
return avail_easyconfig_params_functions[output_format](title, grouped_params)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two blank lines between top-level functions

def generic_easyblocks():
"""
Compose overview of all generic easyblocks
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mention rst

"""
modules = import_available_modules('easybuild.easyblocks.generic')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the package name easybuild.easyblocks.generic should become a parameter of this function, so we can generate an overview of software-specific (i.e. non-generic) easyblocks too

maybe rename function to gen_easyblocks_overview_rst?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or, maybe just add a generic=True named argument, so you can include a matching title

docs = []
seen = []

for m in modules:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no single-letter variable names outside of list comprehensions, use mod or module (make sure module is not a keyword in Python)

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 name not in seen:
docs.append(doc_easyblock(eb_class))
seen.append(name)

toc = ['.. contents:: Available generic easyblocks', ' :depth: 1', '']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop the Available generic easyblocks, we should have a page title in place instead (above the .. contents::)


return toc + sorted(docs)


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insert extra blank line

def doc_easyblock(eb_class):
"""
Compose overview of one easyblock given class object of the easyblock in rst format
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mention rst

"""
classname = eb_class.__name__

common_params = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be a constant, defined on top of this module

'ConfigureMake' : ['configopts', 'buildopts', 'installopts'],
# to be continued
}

lines = [
'``' + classname + '``',
'=' * (len(classname)+4),
'',
]

bases = ['``' + base.__name__ + '``' for base in eb_class.__bases__]
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 ' + backtick(classname) + ' easyblock'
lines.extend([extra_parameters, '-' * len(extra_parameters), ''])
ex_opt = eb_class.extra_options()

titles = ['easyconfig parameter', 'description', 'default value']
values = [[backtick(key) for key in ex_opt], [val[1] for val in ex_opt.values()], [backtick(str(quote_str(val[0]))) for val in ex_opt.values()]]

lines.extend(mk_rst_table(titles, values))
lines.append('')

if classname in common_params:
commonly_used = 'Commonly used easyconfig parameters with ' + backtick(classname) + ' easyblock'
lines.extend([commonly_used, '-' * len(commonly_used)])

for opt in common_params[classname]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use mk_rst_table here too?

param = '* ' + backtick(opt) + ' - ' + DEFAULT_CONFIG[opt][1]
lines.append(param)


if classname + '.eb' in os.listdir(os.path.join(os.path.dirname(__file__), 'doc_examples')):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these need to come from somewhere else, i.e. a location specified as an argument to doc_easyblock (which may need another name, although I can't think of one in 1-2-3)

also, don't include example .eb files here; at best, you can include some in the tests (next to the test easyconfigs we have already), so you can add a unit test for this code

lines.extend(['', 'Example', '-' * 8, '', '::', ''])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make section title Example for <name> easyblock

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and don't hardcode 8, put the section title in a variable and use len

f = open(os.path.join(os.path.dirname(__file__), 'doc_examples', classname+'.eb'), "r")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use read_file(filepath).split('\n')

for line in f.readlines():
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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop emtpy line


def backtick(string):
return '``' + string + '``'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing docstring (and the function is rather silly, not sure if it's worth to define a function for this?