Skip to content

Commit 04426b5

Browse files
committed
Add report_generator module to simplify main. Also, the function to load yaml config file was moved to utils.py to get this info in the main file and create a proper suffix for logging. The main, notebook, and metadata_manager files were updated with these changes. Also, the first version of the logo was included.
1 parent 5352480 commit 04426b5

File tree

9 files changed

+1634
-224
lines changed

9 files changed

+1634
-224
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,5 @@ quarto_report/
171171
# Extra info
172172
UML_diagrams/
173173
Graphical_abstract/
174+
docs/presentations/
174175
test.py

docs/images/vuegen_logo.png

900 KB
Loading

docs/images/vuegen_logo.svg

Lines changed: 1341 additions & 0 deletions
Loading

docs/vuegen_demo.ipynb

Lines changed: 131 additions & 144 deletions
Large diffs are not rendered by default.

vuegen/main.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
1-
from streamlit_reportview import StreamlitReportView
2-
from quarto_reportview import QuartoReportView, ReportFormat
3-
from metadata_manager import MetadataManager
4-
from report import ReportType
5-
from utils import assert_enum_value
1+
import report_generator
2+
from utils import get_logger, load_yaml_config
63

74
if __name__ == '__main__':
8-
# Load report object and metadata from YAML file
9-
yaml_manager = MetadataManager()
10-
report, report_metadata = yaml_manager.load_report_metadata('./report_metadata_micw2graph.yaml')
5+
# Load the YAML configuration file with the report metadata
6+
config_path = "report_metadata_micw2graph.yaml"
7+
report_metadata = load_yaml_config(config_path)
118

12-
# Create report view
13-
doc_report = QuartoReportView(report_metadata['report']['id'],
14-
report_metadata['report']['name'],
15-
report=report,
16-
report_type = assert_enum_value(ReportType, report_metadata['report']['report_type'], report.logger),
17-
report_format = assert_enum_value(ReportFormat, report_metadata['report']['report_format'], report.logger),
18-
columns=None)
19-
doc_report.generate_report()
20-
doc_report.run_report()
9+
# Define logger suffix based on report engine, type and name
10+
report_engine = "streamlit"
11+
report_type = report_metadata['report'].get('report_type')
12+
report_format = report_metadata['report'].get('report_format')
13+
report_name = report_metadata['report'].get('name')
14+
if report_engine == "streamlit":
15+
logger_suffix = f"{report_engine}_report_{report_name}"
16+
else:
17+
logger_suffix = f"{report_type}_{report_format}_report_{report_name}"
2118

22-
# st_report = StreamlitReportView(report_metadata['report']['id'],
23-
# report_metadata['report']['name'],
24-
# report=report,
25-
# report_type = assert_enum_value(ReportType, report_metadata['report']['report_type'], report.logger),
26-
# columns=None)
27-
# st_report.generate_report()
28-
# st_report.run_report()
19+
# Initialize logger
20+
logger = get_logger(f"{logger_suffix}")
21+
22+
# Generate the report
23+
report_generator.get_report(metadata=report_metadata, report_engine=report_engine, logger=logger)
2924

vuegen/metadata_manager.py

Lines changed: 36 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1-
import os
2-
import yaml
31
import report as r
4-
import logging
52
from utils import get_logger, assert_enum_value
63

74
class MetadataManager:
85
"""
96
Class for handling metadata of reports from YAML files and creating report objects.
107
"""
8+
def __init__(self, logger=None):
9+
"""
10+
Initializes the MetadataManager with a logger.
1111
12-
def load_report_metadata(self, file_path: str) -> tuple[r.Report, dict]:
12+
Parameters
13+
----------
14+
logger : logging.Logger, optional
15+
A logger instance for the class. If not provided, a default logger will be created.
1316
"""
14-
Loads metadata from a YAML file, parses it, and returns a Report object and the raw metadata.
17+
self.logger = logger or get_logger("report")
18+
19+
def initialize_report(self, metadata: dict) -> tuple[r.Report, dict]:
20+
"""
21+
Extracts report metadata from a YAML file and returns a Report object and the raw metadata.
1522
1623
Parameters
1724
----------
18-
file_path : str
19-
The path to the YAML file containing the report metadata.
25+
metadata : dict
26+
The report metadata obtained from a YAML file.
2027
2128
Returns
2229
-------
@@ -30,20 +37,6 @@ def load_report_metadata(self, file_path: str) -> tuple[r.Report, dict]:
3037
ValueError
3138
If the YAML file is corrupted or contains missing/invalid values.
3239
"""
33-
# Check the existence of the file_path
34-
if not os.path.exists(file_path):
35-
raise FileNotFoundError(f"The config file at {file_path} was not found.")
36-
37-
# Load the YAML configuration file
38-
with open(file_path, 'r') as file:
39-
try:
40-
metadata = yaml.safe_load(file)
41-
except yaml.YAMLError as exc:
42-
raise ValueError(f"Error parsing YAML file: {exc}")
43-
44-
# Define suffix f"or logger object based on report type and report name
45-
logger_suffix = f"{metadata['report'].get('report_type')}_report_{metadata['report'].get('name')}"
46-
4740
# Create a Report object from metadata
4841
report = r.Report(
4942
id=metadata['report']['id'],
@@ -53,27 +46,25 @@ def load_report_metadata(self, file_path: str) -> tuple[r.Report, dict]:
5346
description=metadata['report'].get('description'),
5447
graphical_abstract=metadata['report'].get('graphical_abstract'),
5548
logo=metadata['report'].get('logo'),
56-
logger = get_logger(logger_suffix)
49+
logger = self.logger
5750
)
5851

5952
# Create sections and subsections
6053
for section_data in metadata.get('sections', []):
61-
section = self._create_section(section_data, report.logger)
54+
section = self._create_section(section_data)
6255
report.sections.append(section)
6356

64-
report.logger.info(f"Report '{report.name}' initialized with {len(report.sections)} sections.")
57+
self.logger.info(f"Report '{report.name}' initialized with {len(report.sections)} sections.")
6558
return report, metadata
6659

67-
def _create_section(self, section_data: dict, logger: logging.Logger) -> r.Section:
60+
def _create_section(self, section_data: dict) -> r.Section:
6861
"""
6962
Creates a Section object from a dictionary of section data.
7063
7164
Parameters
7265
----------
7366
section_data : dict
7467
A dictionary containing section metadata.
75-
logger : logging.Logger
76-
A logger object to track warnings, errors, and info messages.
7768
7869
Returns
7970
-------
@@ -91,21 +82,19 @@ def _create_section(self, section_data: dict, logger: logging.Logger) -> r.Secti
9182

9283
# Create subsections
9384
for subsection_data in section_data.get('subsections', []):
94-
subsection = self._create_subsection(subsection_data, logger)
85+
subsection = self._create_subsection(subsection_data)
9586
section.subsections.append(subsection)
9687

9788
return section
9889

99-
def _create_subsection(self, subsection_data: dict, logger: logging.Logger) -> r.Subsection:
90+
def _create_subsection(self, subsection_data: dict) -> r.Subsection:
10091
"""
10192
Creates a Subsection object from a dictionary of subsection data.
10293
10394
Parameters
10495
----------
10596
subsection_data : dict
10697
A dictionary containing subsection metadata.
107-
logger : logging.Logger
108-
A logger object to track warnings, errors, and info messages.
10998
11099
Returns
111100
-------
@@ -123,59 +112,55 @@ def _create_subsection(self, subsection_data: dict, logger: logging.Logger) -> r
123112

124113
# Create components
125114
for component_data in subsection_data.get('components', []):
126-
component = self._create_component(component_data, logger)
115+
component = self._create_component(component_data)
127116
subsection.components.append(component)
128117

129118
return subsection
130119

131-
def _create_component(self, component_data: dict, logger: logging.Logger) -> r.Component:
120+
def _create_component(self, component_data: dict) -> r.Component:
132121
"""
133122
Creates a Component object from a dictionary of component data.
134123
135124
Parameters
136125
----------
137126
component_data : dict
138127
A dictionary containing component metadata.
139-
logger : logging.Logger
140-
A logger object to track warnings, errors, and info messages.
141128
142129
Returns
143130
-------
144131
Component
145132
A Component object (Plot, DataFrame, or Markdown) populated with the provided metadata.
146133
"""
147134
# Determine the component type
148-
component_type = assert_enum_value(r.ComponentType, component_data['component_type'], logger)
135+
component_type = assert_enum_value(r.ComponentType, component_data['component_type'], self.logger)
149136

150137
# Dispatch to the corresponding creation method
151138
if component_type == r.ComponentType.PLOT:
152-
return self._create_plot_component(component_data, logger)
139+
return self._create_plot_component(component_data)
153140
elif component_type == r.ComponentType.DATAFRAME:
154-
return self._create_dataframe_component(component_data, logger)
141+
return self._create_dataframe_component(component_data)
155142
elif component_type == r.ComponentType.MARKDOWN:
156-
return self._create_markdown_component(component_data, logger)
143+
return self._create_markdown_component(component_data)
157144

158-
def _create_plot_component(self, component_data: dict, logger: logging.Logger) -> r.Plot:
145+
def _create_plot_component(self, component_data: dict) -> r.Plot:
159146
"""
160147
Creates a Plot component.
161148
162149
Parameters
163150
----------
164151
component_data : dict
165152
A dictionary containing plot component metadata.
166-
logger : logging.Logger
167-
A logger object to track warnings, errors, and info messages.
168153
169154
Returns
170155
-------
171156
Plot
172157
A Plot object populated with the provided metadata.
173158
"""
174159
# Validate enum fields
175-
plot_type = assert_enum_value(r.PlotType, component_data['plot_type'], logger)
176-
int_visualization_tool = (assert_enum_value(r.IntVisualizationTool, component_data.get('int_visualization_tool', ''), logger)
160+
plot_type = assert_enum_value(r.PlotType, component_data['plot_type'], self.logger)
161+
int_visualization_tool = (assert_enum_value(r.IntVisualizationTool, component_data.get('int_visualization_tool', ''), self.logger)
177162
if component_data.get('int_visualization_tool') else None)
178-
csv_network_format = (assert_enum_value(r.CSVNetworkFormat, component_data.get('csv_network_format', ''), logger)
163+
csv_network_format = (assert_enum_value(r.CSVNetworkFormat, component_data.get('csv_network_format', ''), self.logger)
179164
if component_data.get('csv_network_format') else None)
180165

181166
# Return the constructed Plot object
@@ -188,27 +173,25 @@ def _create_plot_component(self, component_data: dict, logger: logging.Logger) -
188173
title=component_data.get('title'),
189174
caption=component_data.get('caption'),
190175
csv_network_format=csv_network_format,
191-
logger = logger
176+
logger = self.logger
192177
)
193178

194-
def _create_dataframe_component(self, component_data: dict, logger: logging.Logger) -> r.DataFrame:
179+
def _create_dataframe_component(self, component_data: dict) -> r.DataFrame:
195180
"""
196181
Creates a DataFrame component.
197182
198183
Parameters
199184
----------
200185
component_data : dict
201186
A dictionary containing dataframe component metadata.
202-
logger : logging.Logger
203-
A logger object to track warnings, errors, and info messages.
204187
205188
Returns
206189
-------
207190
DataFrame
208191
A DataFrame object populated with the provided metadata.
209192
"""
210193
# Validate enum field and return dataframe
211-
file_format = assert_enum_value(r.DataFrameFormat, component_data['file_format'], logger)
194+
file_format = assert_enum_value(r.DataFrameFormat, component_data['file_format'], self.logger)
212195
return r.DataFrame(
213196
id=component_data['id'],
214197
name=component_data['name'],
@@ -217,19 +200,17 @@ def _create_dataframe_component(self, component_data: dict, logger: logging.Logg
217200
delimiter=component_data.get('delimiter'),
218201
title=component_data.get('title'),
219202
caption=component_data.get('caption'),
220-
logger = logger
203+
logger = self.logger
221204
)
222205

223-
def _create_markdown_component(self, component_data: dict, logger: logging.Logger) -> r.Markdown:
206+
def _create_markdown_component(self, component_data: dict) -> r.Markdown:
224207
"""
225208
Creates a Markdown component.
226209
227210
Parameters
228211
----------
229212
component_data : dict
230213
A dictionary containing markdown component metadata.
231-
logger : logging.Logger
232-
A logger object to track warnings, errors, and info messages.
233214
234215
Returns
235216
-------
@@ -242,5 +223,5 @@ def _create_markdown_component(self, component_data: dict, logger: logging.Logge
242223
file_path=component_data['file_path'],
243224
title=component_data.get('title'),
244225
caption=component_data.get('caption'),
245-
logger = logger
226+
logger = self.logger
246227
)

vuegen/quarto_reportview.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def run_report(self, output_dir: str = BASE_DIR) -> None:
122122
"""
123123
try:
124124
subprocess.run(["quarto", "render", os.path.join(output_dir, f"{self.BASE_DIR}.qmd")], check=True)
125-
self.report.logger.info(f"'{self.name}' {self.report_type} report rendered with the {self.report_format} format")
125+
self.report.logger.info(f"'{self.name}' '{self.report_type}' report rendered with the '{self.report_format}' format")
126126
except subprocess.CalledProcessError as e:
127127
self.report.logger.error(f"Error running '{self.name}' {self.report_type} report: {str(e)}")
128128
raise

vuegen/report_generator.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Vuegen imports
2+
from streamlit_reportview import StreamlitReportView
3+
from quarto_reportview import QuartoReportView, ReportFormat
4+
from metadata_manager import MetadataManager
5+
from report import ReportType
6+
from utils import assert_enum_value
7+
from enum import StrEnum, auto
8+
import logging
9+
10+
11+
class ReportEngine(StrEnum):
12+
STREAMLIT = auto()
13+
QUARTO = auto()
14+
15+
def get_report(metadata: dict, report_engine: str, logger: logging.Logger) -> None:
16+
"""
17+
Generate and run a report based on the specified engine.
18+
19+
Parameters
20+
----------
21+
metadata : dict
22+
The report metadata obtained from a YAML file.
23+
report_engine : str
24+
The engine to use for generating and displaying the report.
25+
It should be one of the values of the ReportEngine Enum.
26+
logger : logging.Logger
27+
A logger object to track warnings, errors, and info messages.
28+
29+
Raises
30+
------
31+
ValueError
32+
If an unsupported report engine, report type, or report format are provided.
33+
"""
34+
# Validate and convert the report engine to its enum value
35+
validated_engine = assert_enum_value(ReportEngine, report_engine, logger)
36+
37+
# Load report object and metadata from the YAML file
38+
yaml_manager = MetadataManager(logger)
39+
report, report_metadata = yaml_manager.initialize_report(metadata)
40+
41+
# Collect report parameters from YAML file
42+
report_id = report_metadata['report']['id']
43+
report_name = report_metadata['report']['name']
44+
report_type = assert_enum_value(ReportType, report_metadata['report']['report_type'], logger)
45+
46+
# Create and run ReportView object based on its engine
47+
if validated_engine == ReportEngine.STREAMLIT:
48+
st_report = StreamlitReportView(
49+
report_id,
50+
report_name,
51+
report=report,
52+
report_type=report_type,
53+
columns=None
54+
)
55+
st_report.generate_report()
56+
st_report.run_report()
57+
58+
elif validated_engine == ReportEngine.QUARTO:
59+
report_format = assert_enum_value(ReportFormat, report_metadata['report']['report_format'], logger)
60+
doc_report = QuartoReportView(
61+
report_id,
62+
report_name,
63+
report=report,
64+
report_type=report_type,
65+
report_format=report_format,
66+
columns=None
67+
)
68+
doc_report.generate_report()
69+
doc_report.run_report()

0 commit comments

Comments
 (0)