Skip to content

Commit 9d6396c

Browse files
committed
🚧♻️ Refactor creating and writing components streamlit files
- writing of imports + component code (write python file) - component - fct map for generation - building list of components
1 parent ec43047 commit 9d6396c

File tree

1 file changed

+89
-83
lines changed

1 file changed

+89
-83
lines changed

src/vuegen/streamlit_reportview.py

Lines changed: 89 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
from .utils.variables import make_valid_identifier
1414

1515

16+
def write_python_file(fpath: str, imports: list[str], contents: list[str]) -> None:
17+
with open(fpath, "w", encoding="utf8") as f:
18+
# Write imports at the top of the file
19+
f.write("\n".join(imports) + "\n\n")
20+
21+
# Write the subsection content (descriptions, plots)
22+
f.write("\n".join(contents))
23+
24+
1625
class StreamlitReportView(r.WebAppReportView):
1726
"""
1827
A Streamlit-based implementation of the WebAppReportView abstract base class.
@@ -38,6 +47,15 @@ def __init__(
3847
else:
3948
self.report.logger.info("running in a normal Python process")
4049

50+
self.components_fct_map = {
51+
r.ComponentType.PLOT: self._generate_plot_content,
52+
r.ComponentType.DATAFRAME: self._generate_dataframe_content,
53+
r.ComponentType.MARKDOWN: self._generate_markdown_content,
54+
r.ComponentType.HTML: self._generate_html_content,
55+
r.ComponentType.APICALL: self._generate_apicall_content,
56+
r.ComponentType.CHATBOT: self._generate_chatbot_content,
57+
}
58+
4159
def generate_report(
4260
self, output_dir: str = SECTIONS_DIR, static_dir: str = STATIC_FILES_DIR
4361
) -> None:
@@ -338,65 +356,79 @@ def _generate_sections(self, output_dir: str, static_dir: str) -> None:
338356
f"Processing section '{section.id}': '{section.title}' - {len(section.subsections)} subsection(s)"
339357
)
340358

341-
if section.subsections:
342-
# Iterate through subsections and integrate them into the section file
343-
for subsection in section.subsections:
344-
self.report.logger.debug(
345-
f"Processing subsection '{subsection.id}': '{subsection.title} - {len(subsection.components)} component(s)'"
346-
)
347-
try:
348-
# Create subsection file
349-
_subsection_name = make_valid_identifier(subsection.title)
350-
subsection_file_path = (
351-
Path(output_dir)
352-
/ section_name_var
353-
/ f"{_subsection_name}.py"
354-
)
355-
356-
# Generate content and imports for the subsection
357-
subsection_content, subsection_imports = (
358-
self._generate_subsection(
359-
subsection, static_dir=static_dir
360-
)
361-
)
362-
363-
# Flatten the subsection_imports into a single list
364-
flattened_subsection_imports = [
365-
imp for sublist in subsection_imports for imp in sublist
366-
]
367-
368-
# Remove duplicated imports
369-
unique_imports = list(set(flattened_subsection_imports))
370-
371-
# Write everything to the subsection file
372-
with open(subsection_file_path, "w") as subsection_file:
373-
# Write imports at the top of the file
374-
subsection_file.write(
375-
"\n".join(unique_imports) + "\n\n"
376-
)
377-
378-
# Write the subsection content (descriptions, plots)
379-
subsection_file.write("\n".join(subsection_content))
380-
381-
self.report.logger.info(
382-
f"Subsection file created: '{subsection_file_path}'"
383-
)
384-
except Exception as subsection_error:
385-
self.report.logger.error(
386-
f"Error processing subsection '{subsection.id}' '{subsection.title}' in section '{section.id}' '{section.title}': {str(subsection_error)}"
387-
)
388-
raise
389-
else:
359+
if not section.subsections:
390360
self.report.logger.warning(
391-
f"No subsections found in section: '{section.title}'. To show content in the report, add subsections to the section."
361+
f"No subsections found in section: '{section.title}'. "
362+
"To show content in the report, add subsections to the section."
363+
)
364+
continue
365+
366+
# Iterate through subsections and integrate them into the section file
367+
for subsection in section.subsections:
368+
self.report.logger.debug(
369+
f"Processing subsection '{subsection.id}': '{subsection.title} - {len(subsection.components)} component(s)'"
392370
)
371+
try:
372+
# Create subsection file
373+
_subsection_name = make_valid_identifier(subsection.title)
374+
subsection_file_path = (
375+
Path(output_dir)
376+
/ section_name_var
377+
/ f"{_subsection_name}.py"
378+
)
379+
380+
# Generate content and imports for the subsection
381+
subsection_content, subsection_imports = (
382+
self._generate_subsection(subsection)
383+
)
384+
385+
write_python_file(
386+
fpath=subsection_file_path,
387+
imports=subsection_imports,
388+
contents=subsection_content,
389+
)
390+
self.report.logger.info(
391+
f"Subsection file created: '{subsection_file_path}'"
392+
)
393+
except Exception as subsection_error:
394+
self.report.logger.error(
395+
f"Error processing subsection '{subsection.id}' '{subsection.title}' "
396+
f"in section '{section.id}' '{section.title}': {str(subsection_error)}"
397+
)
398+
raise
399+
393400
except Exception as e:
394401
self.report.logger.error(f"Error generating sections: {str(e)}")
395402
raise
396403

397-
def _generate_subsection(
398-
self, subsection, static_dir
399-
) -> tuple[List[str], List[str]]:
404+
def _combine_components(self, components: list[dict]) -> tuple[list, list, bool]:
405+
"""combine a list of components."""
406+
407+
all_contents = []
408+
all_imports = []
409+
has_chatbot = False
410+
411+
for component in components:
412+
# Write imports if not already done
413+
component_imports = self._generate_component_imports(component)
414+
all_imports.extend(component_imports)
415+
416+
# Handle different types of components
417+
fct = self.components_fct_map.get(component.component_type, None)
418+
if fct is None:
419+
self.report.logger.warning(
420+
f"Unsupported component type '{component.component_type}' "
421+
)
422+
else:
423+
if component.component_type == r.ComponentType.CHATBOT:
424+
has_chatbot = True
425+
content = fct(component)
426+
all_contents.extend(content)
427+
# remove duplicates and isort
428+
all_imports = list(set(all_imports))
429+
return all_contents, all_imports, has_chatbot
430+
431+
def _generate_subsection(self, subsection) -> tuple[List[str], List[str]]:
400432
"""
401433
Generate code to render components (plots, dataframes, markdown) in the given subsection,
402434
creating imports and content for the subsection based on the component type.
@@ -430,36 +462,10 @@ def _generate_subsection(
430462
subsection_content.append(
431463
self._format_text(text=subsection.description, type="paragraph")
432464
)
433-
434-
for component in subsection.components:
435-
# Write imports if not already done
436-
component_imports = self._generate_component_imports(component)
437-
subsection_imports.append(component_imports)
438-
439-
# Handle different types of components
440-
if component.component_type == r.ComponentType.PLOT:
441-
subsection_content.extend(
442-
self._generate_plot_content(component, static_dir=static_dir)
443-
)
444-
elif component.component_type == r.ComponentType.DATAFRAME:
445-
subsection_content.extend(self._generate_dataframe_content(component))
446-
# If md files is called "description.md", do not include it in the report
447-
elif (
448-
component.component_type == r.ComponentType.MARKDOWN
449-
and component.title.lower() != "description"
450-
):
451-
subsection_content.extend(self._generate_markdown_content(component))
452-
elif component.component_type == r.ComponentType.HTML:
453-
subsection_content.extend(self._generate_html_content(component))
454-
elif component.component_type == r.ComponentType.APICALL:
455-
subsection_content.extend(self._generate_apicall_content(component))
456-
elif component.component_type == r.ComponentType.CHATBOT:
457-
has_chatbot = True
458-
subsection_content.extend(self._generate_chatbot_content(component))
459-
else:
460-
self.report.logger.warning(
461-
f"Unsupported component type '{component.component_type}' in subsection: {subsection.title}"
462-
)
465+
all_components, subsection_imports, has_chatbot = self._combine_components(
466+
subsection.components
467+
)
468+
subsection_content.extend(all_components)
463469

464470
if not has_chatbot:
465471
# Define the footer variable and add it to the home page content

0 commit comments

Comments
 (0)