"""
Base classes for rendering.
"""
import collections
import functools
from html import escape
from reportlab.platypus import Paragraph
from testplan.common.exporters.pdf import RowData
from . import constants
RowData = functools.partial(RowData, num_columns=constants.NUM_COLUMNS)
[docs]class SlicedParagraph:
"""
Iterator which returns slices of ReportLab Paragraph to make sure each does
not exceed max height (which will trigger ReportLab LayoutError).
:param parts: list of (text, formatter) tuple
:type parts: [(``str``, ``str``), ...]
:param width: width allowed to layout each paragraph
:type width: ``int``
:param height: height allowed to layout each paragraph
:type height: ``int``
:param style: style object for paragraph
:type style: ReportLab ParagraphStyle
"""
def __init__(
self,
parts,
width,
height=constants.MAX_CELL_HEIGHT,
style=constants.PARAGRAPH_STYLE,
**kwargs
):
self.width = width
self.height = height
text_parts = []
if not isinstance(parts, list):
parts = [parts]
for part, formatter in parts:
# reserve indentation - report lab does not wrap at '\n' and removes space
part = (
escape(part, quote=False)
.replace("\n", "<br/>")
.replace(" ", " ")
)
text_parts.append(formatter.format(part))
self.para = Paragraph(text="".join(text_parts), style=style, **kwargs)
def __next__(self):
if self.para:
paras = self.para.split(self.width, self.height)
# paras == [] for empty line
para = paras[0] if paras else ""
self.para = paras[1] if len(paras) == 2 else None
return para
else:
raise StopIteration
def __iter__(self):
return self
[docs]class BaseRowRenderer:
"""Base class for row renderers."""
always_display = False
def __init__(self, style):
self.style = style
[docs] def get_row_data(self, source, depth, row_idx):
"""
Return `RowData` to be rendered on the pdf.
:param source: Source object for the renderer.
:type source: ``report.base.Report`` or ``dict`` (for assertion data).
:param depth: Depth of the source object on report tree.
Used for indentation.
:type depth: ``int``
:param row_idx: Index of the current table row to be rendered.
:type row_idx: ``int``
:return: ``RowData`` object.
:rtype: ``exporters.utils.pdf.RowData``
"""
raise NotImplementedError
[docs] def get_style(self, source):
return self.style.passing
[docs] def should_display(self, source):
"""Use class attribute by default."""
return (
self.always_display
or self.get_style(source).display_assertion_detail
)