mirror of
https://github.com/ARM-software/workload-automation.git
synced 2025-07-15 19:43:28 +01:00
WA3 Exsisting Code
This commit is contained in:
wa
__init__.py
commands
framework
__init__.pyactor.pyagenda.pycommand.py
configuration
entrypoint.pyexception.pyexecution.pyhost.pylog.pyoutput.pyplugin.pypluginloader.pyresource.pyrun.pysignal.pyversion.pyworkload.pytests
__init__.py
data
test_agenda.pytest_config.pytest_diff.pytest_execution.pytest_plugin.pytest_runner.pytest_signal.pytest_utils.pytestutils.pyutils
workloads
307
wa/utils/doc.py
Normal file
307
wa/utils/doc.py
Normal file
@ -0,0 +1,307 @@
|
||||
# Copyright 2014-2015 ARM Limited
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
Utilities for working with and formatting documentation.
|
||||
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import inspect
|
||||
from itertools import cycle
|
||||
|
||||
USER_HOME = os.path.expanduser('~')
|
||||
|
||||
BULLET_CHARS = '-*'
|
||||
|
||||
|
||||
def get_summary(aclass):
|
||||
"""
|
||||
Returns the summary description for an extension class. The summary is the
|
||||
first paragraph (separated by blank line) of the description taken either from
|
||||
the ``descripton`` attribute of the class, or if that is not present, from the
|
||||
class' docstring.
|
||||
|
||||
"""
|
||||
return get_description(aclass).split('\n\n')[0]
|
||||
|
||||
|
||||
def get_description(aclass):
|
||||
"""
|
||||
Return the description of the specified extension class. The description is taken
|
||||
either from ``description`` attribute of the class or its docstring.
|
||||
|
||||
"""
|
||||
if hasattr(aclass, 'description') and aclass.description:
|
||||
return inspect.cleandoc(aclass.description)
|
||||
if aclass.__doc__:
|
||||
return inspect.getdoc(aclass)
|
||||
else:
|
||||
return 'no documentation found for {}'.format(aclass.__name__)
|
||||
|
||||
|
||||
def get_type_name(obj):
|
||||
"""Returns the name of the type object or function specified. In case of a lambda,
|
||||
the definiition is returned with the parameter replaced by "value"."""
|
||||
match = re.search(r"<(type|class|function) '?(.*?)'?>", str(obj))
|
||||
if isinstance(obj, tuple):
|
||||
name = obj[1]
|
||||
elif match.group(1) == 'function':
|
||||
text = str(obj)
|
||||
name = text.split()[1]
|
||||
if name == '<lambda>':
|
||||
source = inspect.getsource(obj).strip().replace('\n', ' ')
|
||||
match = re.search(r'lambda\s+(\w+)\s*:\s*(.*?)\s*[\n,]', source)
|
||||
if not match:
|
||||
raise ValueError('could not get name for {}'.format(obj))
|
||||
name = match.group(2).replace(match.group(1), 'value')
|
||||
else:
|
||||
name = match.group(2)
|
||||
if '.' in name:
|
||||
name = name.split('.')[-1]
|
||||
return name
|
||||
|
||||
|
||||
def count_leading_spaces(text):
|
||||
"""
|
||||
Counts the number of leading space characters in a string.
|
||||
|
||||
TODO: may need to update this to handle whitespace, but shouldn't
|
||||
be necessary as there should be no tabs in Python source.
|
||||
|
||||
"""
|
||||
nspaces = 0
|
||||
for c in text:
|
||||
if c == ' ':
|
||||
nspaces += 1
|
||||
else:
|
||||
break
|
||||
return nspaces
|
||||
|
||||
|
||||
def format_column(text, width):
|
||||
"""
|
||||
Formats text into a column of specified width. If a line is too long,
|
||||
it will be broken on a word boundary. The new lines will have the same
|
||||
number of leading spaces as the original line.
|
||||
|
||||
Note: this will not attempt to join up lines that are too short.
|
||||
|
||||
"""
|
||||
formatted = []
|
||||
for line in text.split('\n'):
|
||||
line_len = len(line)
|
||||
if line_len <= width:
|
||||
formatted.append(line)
|
||||
else:
|
||||
words = line.split(' ')
|
||||
new_line = words.pop(0)
|
||||
while words:
|
||||
next_word = words.pop(0)
|
||||
if (len(new_line) + len(next_word) + 1) < width:
|
||||
new_line += ' ' + next_word
|
||||
else:
|
||||
formatted.append(new_line)
|
||||
new_line = ' ' * count_leading_spaces(new_line) + next_word
|
||||
formatted.append(new_line)
|
||||
return '\n'.join(formatted)
|
||||
|
||||
|
||||
def format_bullets(text, width, char='-', shift=3, outchar=None):
|
||||
"""
|
||||
Formats text into bulleted list. Assumes each line of input that starts with
|
||||
``char`` (possibly preceeded with whitespace) is a new bullet point. Note: leading
|
||||
whitespace in the input will *not* be preserved. Instead, it will be determined by
|
||||
``shift`` parameter.
|
||||
|
||||
:text: the text to be formated
|
||||
:width: format width (note: must be at least ``shift`` + 4).
|
||||
:char: character that indicates a new bullet point in the input text.
|
||||
:shift: How far bulleted entries will be indented. This indicates the indentation
|
||||
level of the bullet point. Text indentation level will be ``shift`` + 3.
|
||||
:outchar: character that will be used to mark bullet points in the output. If
|
||||
left as ``None``, ``char`` will be used.
|
||||
|
||||
"""
|
||||
bullet_lines = []
|
||||
output = ''
|
||||
|
||||
def __process_bullet(bullet_lines):
|
||||
if bullet_lines:
|
||||
bullet = format_paragraph(indent(' '.join(bullet_lines), shift + 2), width)
|
||||
bullet = bullet[:3] + outchar + bullet[4:]
|
||||
del bullet_lines[:]
|
||||
return bullet + '\n'
|
||||
else:
|
||||
return ''
|
||||
|
||||
if outchar is None:
|
||||
outchar = char
|
||||
for line in text.split('\n'):
|
||||
line = line.strip()
|
||||
if line.startswith(char): # new bullet
|
||||
output += __process_bullet(bullet_lines)
|
||||
line = line[1:].strip()
|
||||
bullet_lines.append(line)
|
||||
output += __process_bullet(bullet_lines)
|
||||
return output
|
||||
|
||||
|
||||
def format_simple_table(rows, headers=None, align='>', show_borders=True, borderchar='='): # pylint: disable=R0914
|
||||
"""Formats a simple table."""
|
||||
if not rows:
|
||||
return ''
|
||||
rows = [map(str, r) for r in rows]
|
||||
num_cols = len(rows[0])
|
||||
|
||||
# cycle specified alignments until we have num_cols of them. This is
|
||||
# consitent with how such cases are handled in R, pandas, etc.
|
||||
it = cycle(align)
|
||||
align = [it.next() for _ in xrange(num_cols)]
|
||||
|
||||
cols = zip(*rows)
|
||||
col_widths = [max(map(len, c)) for c in cols]
|
||||
if headers:
|
||||
col_widths = [max(len(h), cw) for h, cw in zip(headers, col_widths)]
|
||||
row_format = ' '.join(['{:%s%s}' % (align[i], w) for i, w in enumerate(col_widths)])
|
||||
row_format += '\n'
|
||||
|
||||
border = row_format.format(*[borderchar * cw for cw in col_widths])
|
||||
|
||||
result = border if show_borders else ''
|
||||
if headers:
|
||||
result += row_format.format(*headers)
|
||||
result += border
|
||||
for row in rows:
|
||||
result += row_format.format(*row)
|
||||
if show_borders:
|
||||
result += border
|
||||
return result
|
||||
|
||||
|
||||
def format_paragraph(text, width):
|
||||
"""
|
||||
Format the specified text into a column of specified with. The text is
|
||||
assumed to be a single paragraph and existing line breaks will not be preserved.
|
||||
Leading spaces (of the initial line), on the other hand, will be preserved.
|
||||
|
||||
"""
|
||||
text = re.sub('\n\n*\\s*', ' ', text.strip('\n'))
|
||||
return format_column(text, width)
|
||||
|
||||
|
||||
def format_body(text, width):
|
||||
"""
|
||||
Format the specified text into a column of specified width. The text is
|
||||
assumed to be a "body" of one or more paragraphs separated by one or more
|
||||
blank lines. The initial indentation of the first line of each paragraph
|
||||
will be presevered, but any other formatting may be clobbered.
|
||||
|
||||
"""
|
||||
text = re.sub('\n\\s*\n', '\n\n', text.strip('\n')) # get rid of all-whitespace lines
|
||||
paragraphs = re.split('\n\n+', text)
|
||||
formatted_paragraphs = []
|
||||
for p in paragraphs:
|
||||
if p.strip() and p.strip()[0] in BULLET_CHARS:
|
||||
formatted_paragraphs.append(format_bullets(p, width))
|
||||
else:
|
||||
formatted_paragraphs.append(format_paragraph(p, width))
|
||||
return '\n\n'.join(formatted_paragraphs)
|
||||
|
||||
|
||||
def strip_inlined_text(text):
|
||||
"""
|
||||
This function processes multiline inlined text (e.g. form docstrings)
|
||||
to strip away leading spaces and leading and trailing new lines.
|
||||
|
||||
"""
|
||||
text = text.strip('\n')
|
||||
lines = [ln.rstrip() for ln in text.split('\n')]
|
||||
|
||||
# first line is special as it may not have the indet that follows the
|
||||
# others, e.g. if it starts on the same as the multiline quote (""").
|
||||
nspaces = count_leading_spaces(lines[0])
|
||||
|
||||
if len([ln for ln in lines if ln]) > 1:
|
||||
to_strip = min(count_leading_spaces(ln) for ln in lines[1:] if ln)
|
||||
if nspaces >= to_strip:
|
||||
stripped = [lines[0][to_strip:]]
|
||||
else:
|
||||
stripped = [lines[0][nspaces:]]
|
||||
stripped += [ln[to_strip:] for ln in lines[1:]]
|
||||
else:
|
||||
stripped = [lines[0][nspaces:]]
|
||||
return '\n'.join(stripped).strip('\n')
|
||||
|
||||
|
||||
def indent(text, spaces=4):
|
||||
"""Indent the lines i the specified text by ``spaces`` spaces."""
|
||||
indented = []
|
||||
for line in text.split('\n'):
|
||||
if line:
|
||||
indented.append(' ' * spaces + line)
|
||||
else: # do not indent emtpy lines
|
||||
indented.append(line)
|
||||
return '\n'.join(indented)
|
||||
|
||||
|
||||
def format_literal(lit):
|
||||
if isinstance(lit, basestring):
|
||||
return '``\'{}\'``'.format(lit)
|
||||
elif hasattr(lit, 'pattern'): # regex
|
||||
return '``r\'{}\'``'.format(lit.pattern)
|
||||
else:
|
||||
return '``{}``'.format(lit)
|
||||
|
||||
|
||||
def get_params_rst(ext):
|
||||
text = ''
|
||||
for param in ext.parameters:
|
||||
text += '{} : {} {}\n'.format(param.name, get_type_name(param.kind),
|
||||
param.mandatory and '(mandatory)' or ' ')
|
||||
desc = strip_inlined_text(param.description or '')
|
||||
text += indent('{}\n'.format(desc))
|
||||
if param.allowed_values:
|
||||
text += indent('\nallowed values: {}\n'.format(', '.join(map(format_literal, param.allowed_values))))
|
||||
elif param.constraint:
|
||||
text += indent('\nconstraint: ``{}``\n'.format(get_type_name(param.constraint)))
|
||||
if param.default:
|
||||
value = param.default
|
||||
if isinstance(value, basestring) and value.startswith(USER_HOME):
|
||||
value = value.replace(USER_HOME, '~')
|
||||
text += indent('\ndefault: {}\n'.format(format_literal(value)))
|
||||
text += '\n'
|
||||
return text
|
||||
|
||||
|
||||
def underline(text, symbol='='):
|
||||
return '{}\n{}\n\n'.format(text, symbol * len(text))
|
||||
|
||||
|
||||
def get_rst_from_extension(ext):
|
||||
text = underline(ext.name, '-')
|
||||
if hasattr(ext, 'description'):
|
||||
desc = strip_inlined_text(ext.description or '')
|
||||
elif ext.__doc__:
|
||||
desc = strip_inlined_text(ext.__doc__)
|
||||
else:
|
||||
desc = ''
|
||||
text += desc + '\n\n'
|
||||
params_rst = get_params_rst(ext)
|
||||
if params_rst:
|
||||
text += underline('parameters', '~') + params_rst
|
||||
return text + '\n'
|
||||
|
Reference in New Issue
Block a user