From 8c2aa882b4adbf67921b6be74f7dc483b1cb2be3 Mon Sep 17 00:00:00 2001
From: Henry Webel
Date: Fri, 23 Jan 2026 16:20:32 +0100
Subject: [PATCH] :art: format with latest black version
---
src/vuegen/quarto_reportview.py | 134 ++++++++---------------
src/vuegen/streamlit_reportview.py | 168 ++++++++---------------------
src/vuegen/utils/__init__.py | 18 ++--
3 files changed, 94 insertions(+), 226 deletions(-)
diff --git a/src/vuegen/quarto_reportview.py b/src/vuegen/quarto_reportview.py
index 5a182ce..c4be7a7 100644
--- a/src/vuegen/quarto_reportview.py
+++ b/src/vuegen/quarto_reportview.py
@@ -223,12 +223,10 @@ def generate_report(self, output_dir: Optional[Path] = None) -> None:
fname_qmd_report = self.output_dir / f"{self.BASE_DIR}.qmd"
with open(fname_qmd_report, "w", encoding="utf-8") as quarto_report:
quarto_report.write(yaml_header)
- quarto_report.write(
- f"""\n```{{python}}
+ quarto_report.write(f"""\n```{{python}}
#| label: 'Imports'
{report_formatted_imports}
-```\n\n"""
- )
+```\n\n""")
quarto_report.write("\n".join(qmd_content))
self.report.logger.info(
"Created qmd script to render the app: %s", fname_qmd_report
@@ -329,8 +327,7 @@ def _create_yaml_header(self) -> str:
A formatted YAML header string customized for the specified output format.
"""
# Base YAML header with title
- yaml_header = textwrap.dedent(
- f"""\
+ yaml_header = textwrap.dedent(f"""\
---
title: {self.report.title}
fig-align: center
@@ -338,13 +335,11 @@ def _create_yaml_header(self) -> str:
echo: false
output: asis
jupyter: python3
- format:"""
- )
+ format:""")
# Define format-specific YAML configurations
# \u007b is { and \u007d is }
format_configs = {
- r.ReportType.HTML: textwrap.dedent(
- f"""
+ r.ReportType.HTML: textwrap.dedent(f"""
html:
toc: true
toc-location: left
@@ -371,12 +366,10 @@ def _create_yaml_header(self) -> str:
| Copyright 2025
{ORG}
- """
- ),
+ """),
# \u007b is { and \u007d is }
r.ReportType.PDF: textwrap.indent(
- textwrap.dedent(
- f"""
+ textwrap.dedent(f"""
pdf:
toc: false
fig-align: center
@@ -390,28 +383,22 @@ def _create_yaml_header(self) -> str:
\\lofoot\u007bThis report was generated with
\\href{{{REPO_URL}}}{{VueGen}} | \\copyright{{}} 2025
\\href{GITHUB_ORG_URL_BRACKETS}\u007b{ORG}\u007d\u007d
- \\rofoot{{\\pagemark}}"""
- ),
+ \\rofoot{{\\pagemark}}"""),
" ",
),
r.ReportType.DOCX: textwrap.indent(
- textwrap.dedent(
- """
+ textwrap.dedent("""
docx:
- toc: false"""
- ),
+ toc: false"""),
" ",
),
r.ReportType.ODT: textwrap.indent(
- textwrap.dedent(
- """
+ textwrap.dedent("""
odt:
- toc: false"""
- ),
+ toc: false"""),
" ",
),
- r.ReportType.REVEALJS: textwrap.dedent(
- f"""
+ r.ReportType.REVEALJS: textwrap.dedent(f"""
revealjs:
toc: false
smaller: true
@@ -439,19 +426,15 @@ def _create_yaml_header(self) -> str:
| Copyright 2025 {ORG}
- """
- ),
+ """),
r.ReportType.PPTX: textwrap.indent(
- textwrap.dedent(
- """
+ textwrap.dedent("""
pptx:
toc: false
- output: true"""
- ),
+ output: true"""),
" ",
),
- r.ReportType.JUPYTER: textwrap.dedent(
- f"""
+ r.ReportType.JUPYTER: textwrap.dedent(f"""
html:
toc: true
toc-location: left
@@ -478,8 +461,7 @@ def _create_yaml_header(self) -> str:
| Copyright 2025 {ORG}
- """
- ),
+ """),
}
# Create a key based on the report type and format
key = self.report_type
@@ -692,36 +674,29 @@ def _generate_plot_code(self, plot, output_file="") -> str:
The generated plot code as a string.
"""
# Initialize plot code with common structure
- plot_code = textwrap.dedent(
- f"""
+ plot_code = textwrap.dedent(f"""
```{{python}}
#| label: '{plot.title} {plot.id}'
#| fig-cap: ""
- """
- )
+ """)
# If the file path is a URL, generate code to fetch content via requests
if is_url(plot.file_path):
- plot_code += textwrap.dedent(
- f"""
+ plot_code += textwrap.dedent(f"""
response = requests.get('{plot.file_path}')
response.raise_for_status()
plot_json = response.text
- """
- )
+ """)
else: # If it's a local file
plot_rel_path = get_relative_file_path(
plot.file_path, relative_to=self.output_dir
).as_posix()
- plot_code += textwrap.dedent(
- f"""
+ plot_code += textwrap.dedent(f"""
with open(report_dir /'{plot_rel_path}', 'r') as plot_file:
plot_json = json.load(plot_file)
-"""
- )
+""")
# Add specific code for each visualization tool
if plot.plot_type == r.PlotType.PLOTLY:
- plot_code += textwrap.dedent(
- """
+ plot_code += textwrap.dedent("""
# Keep only 'data' and 'layout' sections
plot_json = {key: plot_json[key] for key in plot_json
if key in ['data', 'layout']
@@ -737,19 +712,16 @@ def _generate_plot_code(self, plot, output_file="") -> str:
fig_plotly.update_layout(autosize=False, width=950, height=400,
margin=dict(b=50, t=50, l=50, r=50)
)
- """
- )
+ """)
elif plot.plot_type == r.PlotType.ALTAIR:
- plot_code += textwrap.dedent(
- """
+ plot_code += textwrap.dedent("""
# Convert JSON to string
plot_json_str = json.dumps(plot_json)
# Create the altair plot
fig_altair = alt.Chart.from_json(plot_json_str
).properties(width=900, height=370)
- """
- )
+ """)
elif plot.plot_type == r.PlotType.INTERACTIVE_NETWORK:
# Generate the HTML embedding for interactive networks
if is_url(plot.file_path) and plot.file_path.endswith(".html"):
@@ -760,15 +732,13 @@ def _generate_plot_code(self, plot, output_file="") -> str:
)
# Embed the HTML file in an iframe
- plot_code = textwrap.dedent(
- f"""
+ plot_code = textwrap.dedent(f"""
- """
- )
+ """)
return plot_code
def _generate_dataframe_content(self, dataframe) -> List[str]:
@@ -790,15 +760,11 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
dataframe_content.append(f"### {dataframe.title}")
# Append header for DataFrame loading
- dataframe_content.append(
- textwrap.dedent(
- f"""\
+ dataframe_content.append(textwrap.dedent(f"""\
```{{python}}
#| label: '{dataframe.title} {dataframe.id}'
#| fig-cap: ""
- """
- )
- )
+ """))
# Mapping of file extensions to read functions
read_function_mapping = table_utils.read_function_mapping
try:
@@ -856,15 +822,11 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
if sheet_names:
for sheet_name in sheet_names[1:]:
dataframe_content.append(f"#### {sheet_name}")
- dataframe_content.append(
- textwrap.dedent(
- f"""\
+ dataframe_content.append(textwrap.dedent(f"""\
```{{python}}
#| label: '{dataframe.title} {dataframe.id} {sheet_name}'
#| fig-cap: ""
- """
- )
- )
+ """))
dataframe_content.append(
f"df = pd.{read_function.__name__}"
f"(report_dir / '{df_file_path}', "
@@ -913,35 +875,25 @@ def _generate_markdown_content(self, markdown) -> List[str]:
try:
# Initialize md code with common structure
- markdown_content.append(
- textwrap.dedent(
- f"""
+ markdown_content.append(textwrap.dedent(f"""
```{{python}}
#| label: '{markdown.title} {markdown.id}'
#| fig-cap: ""
- """
- )
- )
+ """))
# If the file path is a URL, generate code to fetch content via requests
if is_url(markdown.file_path):
- markdown_content.append(
- textwrap.dedent(
- f"""\
+ markdown_content.append(textwrap.dedent(f"""\
response = requests.get('{markdown.file_path}')
response.raise_for_status()
markdown_content = response.text
- """
- )
- )
+ """))
else: # If it's a local file
md_rel_path = get_relative_file_path(
markdown.file_path, relative_to=self.output_dir
)
- markdown_content.append(
- f"""
+ markdown_content.append(f"""
with open(report_dir / '{md_rel_path.as_posix()}', 'r') as markdown_file:
- markdown_content = markdown_file.read()\n"""
- )
+ markdown_content = markdown_file.read()\n""")
# Code to display md content
markdown_content.append("""display.Markdown(markdown_content)\n```\n""")
@@ -1037,14 +989,12 @@ def _generate_html_content(self, html) -> List[str]:
html_file_path = get_relative_file_path(
html.file_path, relative_to=self.output_dir
)
- iframe_code = textwrap.dedent(
- f"""
+ iframe_code = textwrap.dedent(f"""
- """
- )
+ """)
html_content.append(iframe_code)
except Exception as e:
diff --git a/src/vuegen/streamlit_reportview.py b/src/vuegen/streamlit_reportview.py
index cac5b30..00e8113 100644
--- a/src/vuegen/streamlit_reportview.py
+++ b/src/vuegen/streamlit_reportview.py
@@ -131,38 +131,26 @@ def generate_report(self, output_dir: str = None) -> None:
self.report.logger.debug("Processing app navigation code.")
# Define the Streamlit imports and report manager content
report_manag_content = []
- report_manag_content.append(
- textwrap.dedent(
- """\
+ report_manag_content.append(textwrap.dedent("""\
import os
import time
import psutil
import streamlit as st
- """
- )
- )
+ """))
if self.report.logo:
- report_manag_content.append(
- textwrap.dedent(
- f"""\
+ report_manag_content.append(textwrap.dedent(f"""\
st.set_page_config(layout="wide",
page_title="{self.report.title}",
page_icon="{self.report.logo}"
)
st.logo("{self.report.logo}")
- """
- )
- )
+ """))
else:
- report_manag_content.append(
- textwrap.dedent(
- f"""\
+ report_manag_content.append(textwrap.dedent(f"""\
st.set_page_config(layout="wide",
page_title="{self.report.title}")
- """
- )
- )
+ """))
report_manag_content.append(
self._format_text(
text=self.report.title, type="header", level=1, color="#023858"
@@ -245,9 +233,7 @@ def generate_report(self, output_dir: str = None) -> None:
)
# Add navigation object to the home page content
- report_manag_content.append(
- textwrap.dedent(
- """\
+ report_manag_content.append(textwrap.dedent("""\
report_nav = st.navigation(sections_pages)
# Following https://discuss.streamlit.io/t/\
@@ -265,9 +251,7 @@ def generate_report(self, output_dir: str = None) -> None:
report_nav.run()
- """
- )
- )
+ """))
# Write the navigation and general content to a Python file
with open(
@@ -285,9 +269,7 @@ def generate_report(self, output_dir: str = None) -> None:
fpath = self.section_dir.parent / "README.md"
with open(fpath, "w", encoding="utf-8") as f:
- f.write(
- textwrap.dedent(
- f"""\
+ f.write(textwrap.dedent(f"""\
# Streamlit Report
This report was generated using the Vuegen library:
@@ -299,9 +281,7 @@ def generate_report(self, output_dir: str = None) -> None:
Folder cannot be moved from above path, but can be executed
from anywhere on the system.
- """
- )
- )
+ """))
except Exception as e:
self.report.logger.error(
@@ -425,8 +405,7 @@ def _format_text(
text = text.strip() # get rid of new lines
text = textwrap.indent(text, " ")
- ret = textwrap.dedent(
- f"""\
+ ret = textwrap.dedent(f"""\
st.markdown(
'''
<{tag} style='text-align: {text_align};
@@ -434,8 +413,7 @@ def _format_text(
{tag}>
''',
unsafe_allow_html=True)
- """
- )
+ """)
return ret
def _generate_home_section(
@@ -730,33 +708,23 @@ def _generate_plot_content(self, plot) -> List[str]:
# Determine whether the file path is a URL or a local file
if is_url(html_plot_file):
- plot_content.append(
- textwrap.dedent(
- f"""
+ plot_content.append(textwrap.dedent(f"""
response = requests.get('{html_plot_file}')
response.raise_for_status()
html_content = response.text
- """
- )
- )
+ """))
else:
fpath = get_relative_file_path(
html_plot_file, relative_to=self.section_dir
).as_posix()
- plot_content.append(
- textwrap.dedent(
- f"""
+ plot_content.append(textwrap.dedent(f"""
file_path = (section_dir / '{fpath}').resolve().as_posix()
with open(file_path, 'r') as html_file:
html_content = html_file.read()
- """
- )
- )
+ """))
# Append the code for additional information (nodes and edges count)
- plot_content.append(
- textwrap.dedent(
- f"""
+ plot_content.append(textwrap.dedent(f"""
st.markdown((" "
"Number of nodes: {num_nodes}
"),
unsafe_allow_html=True)
@@ -764,9 +732,7 @@ def _generate_plot_content(self, plot) -> List[str]:
" Number of relationships: {num_edges}"
"
"),
unsafe_allow_html=True)
- """
- )
- )
+ """))
# Add the specific code for visualization
plot_content.append(self._generate_plot_code(plot))
@@ -807,27 +773,22 @@ def _generate_plot_code(self, plot) -> str:
"""
# If the file path is a URL, generate code to fetch content via requests
if is_url(plot.file_path):
- plot_code = textwrap.dedent(
- f"""
+ plot_code = textwrap.dedent(f"""
response = requests.get('{plot.file_path}')
response.raise_for_status()
- plot_json = json.loads(response.text)\n"""
- )
+ plot_json = json.loads(response.text)\n""")
else: # If it's a local file
plot_rel_path = get_relative_file_path(
plot.file_path, relative_to=self.section_dir
).as_posix()
- plot_code = textwrap.dedent(
- f"""
+ plot_code = textwrap.dedent(f"""
file_path = (section_dir / '{plot_rel_path}').resolve().as_posix()
with open(file_path, 'r') as plot_file:
- plot_json = json.load(plot_file)\n"""
- )
+ plot_json = json.load(plot_file)\n""")
# Add specific code for each visualization tool
if plot.plot_type == r.PlotType.PLOTLY:
- plot_code += textwrap.dedent(
- """
+ plot_code += textwrap.dedent("""
# Keep only 'data' and 'layout' sections
plot_json = {key: plot_json[key] for key in plot_json
if key in ['data', 'layout']}
@@ -835,26 +796,21 @@ def _generate_plot_code(self, plot) -> str:
# Remove 'frame' section in 'data'
plot_json['data'] = [{k: v for k, v in entry.items() if k != 'frame'}
for entry in plot_json.get('data', [])]
- st.plotly_chart(plot_json, use_container_width=True)\n"""
- )
+ st.plotly_chart(plot_json, use_container_width=True)\n""")
elif plot.plot_type == r.PlotType.ALTAIR:
- plot_code += textwrap.dedent(
- """
+ plot_code += textwrap.dedent("""
altair_plot = alt.Chart.from_dict(plot_json)
st.vega_lite_chart(json.loads(altair_plot.to_json()),
- use_container_width=True)\n"""
- )
+ use_container_width=True)\n""")
elif plot.plot_type == r.PlotType.INTERACTIVE_NETWORK:
- plot_code = textwrap.dedent(
- """\
+ plot_code = textwrap.dedent("""\
# Streamlit checkbox for controlling the layout
control_layout = st.checkbox('Add panel to control layout', value=True)
net_html_height = 1200 if control_layout else 630
# Load HTML into HTML component for display on Streamlit
- st.components.v1.html(html_content, height=net_html_height)\n"""
- )
+ st.components.v1.html(html_content, height=net_html_height)\n""")
return plot_code
def _generate_dataframe_content(self, dataframe) -> List[str]:
@@ -914,17 +870,13 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
fpath = get_relative_file_path(
dataframe.file_path, relative_to=self.section_dir
).as_posix()
- dataframe_content.append(
- textwrap.dedent(
- f"""\
+ dataframe_content.append(textwrap.dedent(f"""\
file_path = (section_dir / '{fpath}').resolve().as_posix()
sheet_names = table_utils.get_sheet_names(file_path)
selected_sheet = st.selectbox("Select a sheet to display",
options=sheet_names,
)
- """
- )
- )
+ """))
# Load the DataFrame using the correct function
df_file_path = get_relative_file_path(
@@ -935,14 +887,10 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
r.DataFrameFormat.XLS.value_with_dot,
r.DataFrameFormat.XLSX.value_with_dot,
]:
- dataframe_content.append(
- textwrap.dedent(
- f"""\
+ dataframe_content.append(textwrap.dedent(f"""\
file_path = (section_dir / '{df_file_path}').resolve()
df = pd.{read_function}(file_path, sheet_name=selected_sheet)
- """
- )
- )
+ """))
else:
dataframe_content.append(
f"file_path = (section_dir / '{df_file_path}'"
@@ -951,9 +899,7 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
)
# ! Alternative to select box: iterate over sheets in DataFrame
# Displays a DataFrame using AgGrid with configurable options.
- dataframe_content.append(
- textwrap.dedent(
- """
+ dataframe_content.append(textwrap.dedent("""
# Displays a DataFrame using AgGrid with configurable options.
grid_builder = GridOptionsBuilder.from_dataframe(df)
grid_builder.configure_default_column(editable=True,
@@ -980,9 +926,7 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
file_name=f"dataframe_{df_index}.csv",
mime='text/csv',
key=f"download_button_{df_index}")
- df_index += 1"""
- )
- )
+ df_index += 1"""))
except Exception as e:
self.report.logger.error(
"Error generating content for DataFrame: %s. Error: %s",
@@ -1031,29 +975,21 @@ def _generate_markdown_content(self, markdown) -> List[str]:
try:
# If the file path is a URL, generate code to fetch content via requests
if is_url(markdown.file_path):
- markdown_content.append(
- textwrap.dedent(
- f"""
+ markdown_content.append(textwrap.dedent(f"""
response = requests.get('{markdown.file_path}')
response.raise_for_status()
markdown_content = response.text
- """
- )
- )
+ """))
else: # If it's a local file
md_rel_path = get_relative_file_path(
markdown.file_path, relative_to=self.section_dir
).as_posix()
- markdown_content.append(
- textwrap.dedent(
- f"""
+ markdown_content.append(textwrap.dedent(f"""
file_path = (section_dir / '{md_rel_path}').resolve().as_posix()
with open(file_path, 'r') as markdown_file:
markdown_content = markdown_file.read()
- """
- )
- )
+ """))
# Code to display md content
markdown_content.append(
"st.markdown(markdown_content, unsafe_allow_html=True)\n"
@@ -1105,28 +1041,20 @@ def _generate_html_content(self, html) -> List[str]:
try:
if is_url(html.file_path):
# If it's a URL, fetch content dynamically
- textwrap.dedent(
- html_content.append(
- f"""
+ textwrap.dedent(html_content.append(f"""
response = requests.get('{html.file_path}')
response.raise_for_status()
html_content = response.text
- """
- )
- )
+ """))
else: # If it's a local file
html_rel_path = get_relative_file_path(
html.file_path, relative_to=self.section_dir
).as_posix()
- html_content.append(
- textwrap.dedent(
- f"""\
+ html_content.append(textwrap.dedent(f"""\
file_path = (section_dir / '{html_rel_path}').resolve().as_posix()
with open(file_path, 'r', encoding='utf-8') as f:
html_content = f.read()
- """
- )
- )
+ """))
# Display HTML content using Streamlit
html_content.append(
@@ -1284,8 +1212,7 @@ def _generate_chatbot_content(self, chatbot) -> List[str]:
if chatbot.model:
# --- Ollama-style streaming chatbot ---
# all other codeblocks pasted in need to be on this indentation level
- code_block = textwrap.dedent(
- f"""
+ code_block = textwrap.dedent(f"""
{init_messages_block}
# Function to send prompt to Ollama API
def generate_query(messages):
@@ -1334,14 +1261,12 @@ def response_generator(msg_content):
st.session_state.messages.append(parsed_response)
with st.chat_message("assistant"):
st.write_stream(response_generator(parsed_response["content"]))
- """
- )
+ """)
chatbot_content.append(code_block)
else:
# --- Standard (non-streaming) API chatbot ---
- code_block = textwrap.dedent(
- f"""
+ code_block = textwrap.dedent(f"""
{init_messages_block}
# Function to send prompt to standard API
@@ -1391,8 +1316,7 @@ def generate_query(prompt):
)
else:
st.error("Failed to get response from API")
- """
- )
+ """)
chatbot_content.append(code_block)
if chatbot.caption:
diff --git a/src/vuegen/utils/__init__.py b/src/vuegen/utils/__init__.py
index 86c638b..78f4634 100644
--- a/src/vuegen/utils/__init__.py
+++ b/src/vuegen/utils/__init__.py
@@ -835,8 +835,7 @@ def get_completion_message(report_type: str, config_path: str) -> str:
border = "─" * 65 # Creates a separator line
if report_type == "streamlit":
- message = textwrap.dedent(
- f"""
+ message = textwrap.dedent(f"""
🚀 Streamlit Report Generated!
📂 All scripts to build the Streamlit app are available at:
@@ -853,11 +852,9 @@ def get_completion_message(report_type: str, config_path: str) -> str:
⚙️ Configuration file used:
{config_path}
- """
- )
+ """)
else:
- message = textwrap.dedent(
- f"""
+ message = textwrap.dedent(f"""
🚀 {report_type.capitalize()} Report Generated!
📂 Your {report_type} report is available at:
@@ -871,8 +868,7 @@ def get_completion_message(report_type: str, config_path: str) -> str:
⚙️ Configuration file used:
{config_path}
- """
- )
+ """)
return f"{message}\n{border}"
@@ -891,8 +887,7 @@ def generate_footer() -> str:
str
A formatted HTML string representing the footer.
"""
- footer = textwrap.dedent(
- f"""
+ footer = textwrap.dedent(f"""