Commit 6b50a486 authored by Lukas Riedel's avatar Lukas Riedel Committed by Santiago Ospina De Los Ríos

Write objects instead of tables in RST writer

The RST writer now writes a single object per parameter instead of
merging all parameters of a category into a single table. This makes
the config file parameter documentation more flexible and readable.
The description input may contain paragraph breaks and indented list
which will be properly obeyed in the resulting RST output.
parent bfb934d0
......@@ -232,10 +232,10 @@ adding an empty line, make text **bold** or ``monospaced``.
<definition> Upwinding method for skeleton terms. Upwinding typically
increases numeric stability while reducing accuracy.
**semiUpwind:** Apply upwinding to conductivity factor (only).
* **semiUpwind:** Apply upwinding to conductivity factor (only).
**fullUpwind:** Apply upwinding to conductivity.
**Not recommended for DG**.
* **fullUpwind:** Apply upwinding to conductivity.
**Not recommended for DG**.
</definition>
<values> none, semiUpwind, fullUpwind </values>
<suggestion> none </suggestion>
......@@ -246,13 +246,13 @@ adding an empty line, make text **bold** or ``monospaced``.
<parameter name="DGMethod">
<definition> DG discretization method for skeleton terms.
**SIPG:** Symmetric Interior Penalty
* **SIPG:** Symmetric Interior Penalty
**NIPG:** Non-Symmetric Interior Penalty
* **NIPG:** Non-Symmetric Interior Penalty
**OBB:** Oden, Babuska, Baumann: no penalty term
* **OBB:** Oden, Babuska, Baumann: no penalty term
**IIP:** Incomplete Interior Penalty: no symmetry term
* **IIP:** Incomplete Interior Penalty: no symmetry term
</definition>
<values> SIPG, NIPG, OBB, IIP </values>
<suggestion> SIPG </suggestion>
......
......@@ -2,7 +2,7 @@ Configuration File Guide
************************
.. contents::
:depth: 2
:depth: 3
.. _inifile-syntax:
......
......@@ -3,6 +3,7 @@ from __future__ import unicode_literals
import datetime
import os
import re
import textwrap
try:
str = unicode
......@@ -13,69 +14,88 @@ from dorie.utilities.check_path import check_path
from dorie.parscraper.parameter import Parameter
def write(parameters,out,path_base,*args,**kwargs):
"""
Writes the contents of the ``parameters`` input dict to a .rst file. The output is
structured as
"""Writes the contents of the ``parameters`` input dict to a .rst file. The
output is structured as
**category**
Category: ``<category>``
============ =============== =============== =============== =================
Parameter Definition Possible values Default Queried at
============ =============== =============== =============== =================
p.key p.definition p.values p.suggestion all sources of p
============ =============== =============== =============== =================
.. object:: <parameter>
:param dict parameters: dict with categories as keys and iterables of :class:`dorie.parscraper.parameter.Parameter` \
instances as values.
:param str out: Path to the output file. Must be writable.
:param str path_base: Base path to the source files. Needed for creation of working links \
to the files.
<description>
"""
Possible values | <values>
Default value | <suggestion>
Queried at | <file path (if available)>
# DEFINE OUTPUT PROPERTIES
headings = ["Parameter","Definition","Possible values","Default","Queried at"]
widths = ["15","45","20","10","10"] # relative column widths
The description obeys paragraph breaks in the description and properly
formats list indentations.
table_content = lambda p: (p.key,p.definition,p.values,p.suggestion,_sources(p,path_base))
Args:
parameters (dict): Keys: category, Values: iterables of
:class:`dorie.parscraper.parameter.Parameter` instances.
out (str): Path to the output file. Must be writable.
path_base (str): Base path to the source files. Required for working
links to the files.
"""
check_path(out)
with open(out,"wb") as output:
rst_document = _format_rst(parameters, headings, widths, table_content)
rst_document = _format_rst(parameters, path_base)
output.write(rst_document.encode('utf-8'))
def _format_rst(parameters,headers,widths,content_function):
def _format_rst(parameters, path_base):
rst = u""
for category in parameters:
rst += _format_heading(category)
table_content = [content_function(p) for p in parameters[category]]
rst += _format_table(table_content,headers,widths)
for param in parameters[category]:
rst += _format_parameter(param, path_base)
return rst
def _format_table(content,headers,widths):
tab = " "
delimiter = ","
table = u""
table += ".. csv-table::\n"
table += tab + ":header: {}\n".format(", ".join(headers))
table += tab + ":delim: {}\n".format(delimiter)
table += tab + ":widths: {}\n".format(", ".join(widths))
table += tab + "\n"
for row in content:
row = ['"{}"'.format(str(s).strip()) for s in row]
row_csv = "{} ".format(delimiter).join(row)
row_csv = re.sub(r"\n","\n" + tab,row_csv)
table += tab + row_csv
table += tab + "\n"
table += "\n\n"
return table
def _format_title(text):
sep = "="*len(text)
return sep + "\n" + text + "\n" + sep + "\n\n"
def _format_parameter(parameter, path_base):
tab = " " # Three spaces to match with 'object' indentation
# Headline
out = u""
out += ".. object:: {}\n\n".format(parameter.key)
# Description
# Double newlines are paragraph splits
merged_paragraphs = _merge_lines(parameter.definition.strip().splitlines())
for paragraph in merged_paragraphs:
indent = " " if paragraph.startswith('*') \
or paragraph.startswith('-') \
else ""
for line in textwrap.wrap(paragraph, subsequent_indent=indent):
out += tab + line + "\n"
out += "\n"
out += "\n"
# Table
out += tab + ".. list-table::\n"
out += tab + tab + ":widths: auto\n\n"
out += tab + tab + "* - *Possible values*\n"
out += tab + tab + " - {}\n".format(parameter.values)
out += tab + tab + "* - *Default value*\n"
out += tab + tab + " - {}\n".format(parameter.suggestion)
# State sources
out += tab + tab + "* - *Queried at*\n"
out += tab + tab + " -"
source_list = _sources(parameter, path_base)
for line in source_list:
out += " | " + line + "\n" + tab + tab + " "
if not source_list:
# Do not delete last line (contains empty column)
out += "\n\n"
# remove final line
out = out[:out.rfind('\n')]
out += "\n\n\n"
return out
def _format_heading(text):
text = "Category: ``{}``".format(text)
sep = "+"*len(text)
return text + "\n" + sep + "\n\n"
......@@ -86,20 +106,43 @@ def _sources(p,path_base):
into a printable RST format. Prints a link to each source file, the
corresponding line number, and concatenates them with newlines.
Returns a unicode string containing the RST code.
:Returns:
List of unicode strings, each containing one line of source file link
without indentation or newline characters.
:param p: Parameter object.
"""
out = u""
out = []
for source_file, line_num, var_type in p._sources:
full_path = os.path.join(path_base,source_file)
# truncate long file names
if len(source_file) > 20:
link_text = "..." + source_file[-20:]
if len(source_file) > 40:
link_text = "..." + source_file[-40:]
else:
link_text = source_file
out += "`{0} <file://{2}>`_:{1}\n\n"\
.format(link_text,line_num,full_path,source_file)
out.append(u"`{0}#L{1} <file://{2}>`_".format(link_text,
line_num,
full_path))
return out
def _merge_lines(lines):
"""Merges lines which are not separated by an empty line and returns
the resulting list.
Args:
lines (list): List of strings, each representing one line.
Returns:
list: List of strings, each representing one line.
"""
result = [""]
for line in lines:
if line:
result[-1] = " ".join((result[-1], line))
else:
result.append("")
return [line.strip() for line in result if line]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment