Skip to content

Variant

Report variant is a unique combination of sections sequence and settings that can be used to produce a final variant of a report document. It can be defined as a separate JSON file, and provided on the Report object initialization.

Difference between report type and report variant

It's important to distinguish the difference between the report type and report variant. Report type is child of a Report class that specifies which sections are available for usage, and what data object can be utilized by those sections as data sources. On the other hand, report variant specifies the order and configuration of those sections that makes a final structure of the report.

In other words, report type defines what is possible to generate while report variant uses those possibilities to define the concrete definition of report structure.

For example, report type is a Motor Asset Report that defines all possible sections and data objects available in that context, while the report variant of that report is Instant motor asset report, that specifies which sections in which order and with which settings should be used to prepare a specific variant of the report document.

There might be several variants of each report type. They might be predefined and come from the smartreport package itself, or custom / user made and provided from outside to the report generation process.

Report variant model

Report variant is provided to the Report class at object initialization. Depending on the report settings there might be a default report variant for a given report type, but preferably, the variant is explicitly provided.

In the codebase, the report variant is represented by Pydantic models

smartreport.v3.reports.variant.ReportVariantDefinition

Source code in smartreport/v3/reports/variant.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class ReportVariantDefinition(BaseModel):
    sections: List[ReportSectionDefinition]
    settings: Dict[str, Any] = Field(default_factory=dict)

    def get_section_by_name(self, section_name: str) -> ReportSectionDefinition:
        for s in self.sections:
            if s.name == section_name:
                return s

        raise KeyError(f"Section {section_name} not found")

    def update_section_settings(
        self, section_name: str, excluded_values: Sequence[Any] = (None, ""), **kwargs
    ) -> None:
        try:
            section = self.get_section_by_name(section_name=section_name)
            valid_kwargs = {k: v for k, v in kwargs.items() if v not in excluded_values}
            section.settings.update(**valid_kwargs)
        except KeyError:
            return None

and

smartreport.v3.reports.variant.ReportSectionDefinition

Source code in smartreport/v3/reports/variant.py
 6
 7
 8
 9
10
11
12
13
14
15
16
class ReportSectionDefinition(BaseModel):
    name: str
    description: str = ""
    skip: bool = False
    settings: Dict[str, Any] = Field(default_factory=dict)

    @property
    def class_name(self):
        clean_name = self.name.replace(" ", "_")
        section_class_name = f"{clean_name}Section"
        return section_class_name

Report variant from JSON file

Although, the report variant model can be initialized in Python code, in real life scenario it's rather provided as an JSON file.

This file provides both the sections order and sections' custom settings if needed. In the example below you can see that the TOC_DEPTH parameter for "TOC" section is overriden to 1 in this report variant file.

Every existing section parameter can be configured in this way.

Example

{
  "settings": {
  },
  "sections": [
    {
      "name": "Title",
      "settings": {
        "SUB_TITLE": "Expert asset report for motor"
      }
    },
    {
      "name": "ReportOverviewTable"
    },
    {
      "name": "TOC",
      "settings": {
        "TOC_DEPTH": 1
      }
    }
  ]
}

To provide the report variant file to the report object as string, path, dictionary or already parsed ReportVariantDefinition object.

asset = MotorAsset(
    asset_id=7722,
    asset_data_reader=adr,
    start_date="2022-01-01",
    end_date="2022-02-01",
)
output = "word"
path_to_variant_file = r"D:\Variants\instant_asset_motor_variant.json"

report = MotorAssetReport(
    asset=asset,
    report_output=output,
    report_variant=path_to_variant_file,
)

report.make_report()