Section
Sections are the building blocks of report object. Each report is made of sequence of sections, initialized with data object (e.g. Asset, Fleet or Drive), that were provided by Report object, and custom settings if needed.
Section might be reused between the different report types, as long as the attributes available in the report object
are compatible with the interface of the section's .create() method.
Settings
The section class has an inner class with settings adopted to the section needs. Every setting has a default value, so even without any adjustment, a section can be included in the report.
However, in many cases the setting customization is needed. It might be applied at different stages of the report preparation.
Section settings are defined as Pydantic models. Thanks to that, input parsing, based on type annotations, is available. This is particularly useful when the settings are provided from outside the Python code, e.g. from the JSON based report variant file. When a section requires a setting that is an integer, it can be provided as a string or float as long as it can be parsed to a valid integer type.
Section defaults in report settings
If you need to redefine the defaults of the section used in the newly created report, you can provide the new defaults
in the SECTION_DEFAULTS parameter of the report settings. The provided defaults will replace the original one, while
those that were not provided will remain untouched.
In the example below the NewReport class has Settings defined with a SECTION_DEFAULTS parameter, that
will use KPI_IDS=["10", "20", "30"] default for the "EquipmentView" section and a custom IMAGE_PATH for the "Title"
section.
All other sections used in this report will have a default settings. Also, other settings for the "EquipmentView", and "Title" sections will not be altered.
Example
class NewReport(Report):
from smartreport.v3.reports.new_report import sections
class Settings(Report.Settings):
SECTION_DEFAULTS: Dict[str, ReportSection.Settings] = {
"EquipmentView": sections.EquipmentViewSection.Settings(KPI_IDS=["10", "20", "30"]),
"Title": sections.TitleSection.Settings(IMAGE_PATH=STATIC_FOLDER_PATH / "new_report_picture.jpg"),
}
Section settings in report variant
Quite often we want to define several variants of given report type. Variant are build from the same poll of sections, but they might come in different order or setup.
It is also useful, if the variants can be defined outside the Python code. This way the non-developer users can also contribute to the report defining process. This is allowed by supporting the JSON based variant definition.
In order to enable the section settings customisation from JSON file, the report object builder can get the section
settings from the file, and override the section defaults, coming both from the section itself
or the SECTION_DEFAULTS setting in the Report settings.
In the example bellow the JSON file that defines the report variant has overriden some settings
for "VibrationSignalsFFT" section. The NO_OF_HIGHEST_PEAKS will be equal to 3, and VELOCITY_SPECTRA_LIMIT
will be equal to 1200 in that report variant.
Other section will be used with its default values.
Example
{
"config": {
"SUB_TITLE": "Instant asset report for motor"
},
"sections": [
{
"name": "Title"
},
{
"name": "TOC"
},
{
"name": "VibrationSignalsTime"
},
{
"name": "VibrationSignalsFFT",
"settings": {
"NO_HIGHEST_PEAKS": 3,
"VELOCITY_SPECTRA_LIMIT": 1200.0
}
}
]
}
Section settings in the report generation call
TO BE DONE
Creating new section
To create a new section you have to create a new Python class that inherits from ReportSection class.
Usually, it should be placed in a separate file in the sections submodule.
Below you can see a full example of "TOCSection"
from smartreport.engine.translations import _
from smartreport.v3.reports.report import ReportSection
class TOCSection(ReportSection):
"""
Adds automatic Table of Content to the report.
"""
class Settings(ReportSection.Settings):
"""
Attributes:
TOC_DEPTH (int): Depth of Table of content.
It means, how many levels of headings should be used
to create table of content.
"""
TOC_DEPTH: int = 2
settings: Settings
def create(self) -> None:
self.report_output.add_heading(text=_("Table of Content"), level=1)
self.report_output.add_toc(depth=self.settings.TOC_DEPTH)
self.report_output.add_page_break()
In order to enable the for the given report type to be used, it has to be imported in the Report class body.
from smartreport.v3.reports.new_report.sections.visualize_data import VisualizeDataSection
from smartreport.v3.reports.new_report.sections.rul import RemainingUsefullLifetimeSection
class NewReport(Report):
from smartreport.v3.reports.new_report import sections
Testing
Since the report section is an independent object it can be tested outside the report context. Each section can produce its own piece of report document, that can be verified without the need of generating the full report.
Sections can be tested independently of each other. If needed, the custom settings can be defined on section initialization.
Most suitable data source and report output can be used. e.g. JSON ReportOutput and Mocked Assert
ReportSection implements the .test() method that returns a document with this section's content only.
Example
from hypothesis import given, strategies as st
from smartreport.engine.outputs.json_document import JSONReportOutput
from smartreport.v3.reports.common.sections import TitleSection
class TestTitleSectionSection:
def test_default_section_creation(self):
ro = JSONReportOutput()
section = TitleSection(report_output=ro)
test_out = section.test()
# Paragraph([Span(ABB_CURSOR_CHAR)])
assert test_out.document[0].data[0].data == section.settings.ABB_CURSOR_CHAR
# Paragraph([Span(REPORT_PROVIDER)])
assert test_out.document[1].data[0].data == section.settings.REPORT_PROVIDER
# Paragraph([Span(MAIN_TITLE)])
assert test_out.document[2].data[0].data == section.settings.MAIN_TITLE
# Paragraph([Span(SUB_TITLE)])
assert test_out.document[3].data[0].data == section.settings.SUB_TITLE
# Pictures([Image(path=IMAGE_PATH) as B64 string])
assert test_out.document[4].data[0] == ro._pic_to_b64(
picture=section.settings.IMAGE_PATH)
@given(sub_title=st.text(min_size=1, max_size=200))
def test_custom_sub_title(self, sub_title):
section = TitleSection(
report_output=JSONReportOutput(),
settings=TitleSection.Settings(SUB_TITLE=sub_title))
test_out = section.test()
assert test_out.document[3].data[0].data == section.settings.SUB_TITLE
Documentation
Each section is automatically documented, including settings specification. Based on specific report variant definition a full report documentation can be generated.
This requires from the section creator to provide a comprehensive docstring, and is automatically converted to
documentation thanks to mkdocsting package.
Check Sections documentation pages for some examples.