@@ -25,6 +25,7 @@ def __init__(
2525 report : r .Report ,
2626 report_type : r .ReportType ,
2727 quarto_checks : bool = False ,
28+ output_dir : Optional [Path ] = BASE_DIR ,
2829 static_dir : str = STATIC_FILES_DIR ,
2930 ):
3031 """_summary_
@@ -44,6 +45,7 @@ def __init__(
4445 super ().__init__ (report = report , report_type = report_type )
4546 self .quarto_checks = quarto_checks
4647 self .static_dir = static_dir
48+ self .output_dir = output_dir .resolve ().absolute ()
4749 # self.BUNDLED_EXECUTION = False
4850 self .quarto_path = "quarto"
4951 # self.env_vars = os.environ.copy()
@@ -72,25 +74,28 @@ def __init__(
7274 r .ComponentType .HTML : self ._generate_html_content ,
7375 }
7476
75- def generate_report (self , output_dir : Path = BASE_DIR ) -> None :
77+ def generate_report (self , output_dir : Optional [ Path ] = None ) -> None :
7678 """
7779 Generates the qmd file of the quarto report. It creates code for rendering each section and its subsections with all components.
7880
7981 Parameters
8082 ----------
8183 output_dir : Path, optional
82- The folder where the generated report files will be saved (default is BASE_DIR).
84+ The folder where the generated report files will be saved.
85+ Will overwrite value set on initialization of QuartoReportView.
8386 """
87+ if output_dir is not None :
88+ self .output_dir = Path (output_dir ).resolve ().absolute ()
89+
8490 self .report .logger .debug (
85- f"Generating '{ self .report_type } ' report in directory: '{ output_dir } '"
91+ f"Generating '{ self .report_type } ' report in directory: '{ self . output_dir } '"
8692 )
87-
8893 # Create the output folder
89- if create_folder (output_dir ):
90- self .report .logger .debug (f"Created output directory: '{ output_dir } '" )
94+ if create_folder (self . output_dir , is_nested = True ):
95+ self .report .logger .debug (f"Created output directory: '{ self . output_dir } '" )
9196 else :
9297 self .report .logger .debug (
93- f"Output directory already existed: '{ output_dir } '"
98+ f"Output directory already existed: '{ self . output_dir } '"
9499 )
95100
96101 # Create the static folder
@@ -207,6 +212,9 @@ def generate_report(self, output_dir: Path = BASE_DIR) -> None:
207212 self .report .logger .warning (
208213 f"No subsections found in section: '{ section .title } '. To show content in the report, add subsections to the section."
209214 )
215+ # Add globally set output folder
216+ report_imports .append ("from pathlib import Path" )
217+ report_imports .append ("report_dir = Path().cwd()" )
210218
211219 # Remove duplicated imports
212220 report_unique_imports = set (report_imports )
@@ -224,7 +232,8 @@ def generate_report(self, output_dir: Path = BASE_DIR) -> None:
224232 report_formatted_imports = "\n " .join (report_unique_imports )
225233
226234 # Write the navigation and general content to a Python file
227- with open (Path (output_dir ) / f"{ self .BASE_DIR } .qmd" , "w" ) as quarto_report :
235+ fname_qmd_report = self .output_dir / f"{ self .BASE_DIR } .qmd"
236+ with open (fname_qmd_report , "w" ) as quarto_report :
228237 quarto_report .write (yaml_header )
229238 quarto_report .write (
230239 f"""\n ```{{python}}
@@ -234,7 +243,7 @@ def generate_report(self, output_dir: Path = BASE_DIR) -> None:
234243 )
235244 quarto_report .write ("\n " .join (qmd_content ))
236245 self .report .logger .info (
237- f"Created qmd script to render the app: { self . BASE_DIR } .qmd "
246+ f"Created qmd script to render the app: { fname_qmd_report } "
238247 )
239248
240249 except Exception as e :
@@ -243,7 +252,7 @@ def generate_report(self, output_dir: Path = BASE_DIR) -> None:
243252 )
244253 raise
245254
246- def run_report (self , output_dir : str = BASE_DIR ) -> None :
255+ def run_report (self , output_dir : Optional [ Path ] = None ) -> None :
247256 """
248257 Runs the generated quarto report.
249258
@@ -253,8 +262,10 @@ def run_report(self, output_dir: str = BASE_DIR) -> None:
253262 The folder where the report was generated (default is 'sections').
254263 """
255264 # from quarto_cli import run_quarto # entrypoint of quarto-cli not in module?
265+ if output_dir is not None :
266+ self .output_dir = Path (output_dir ).resolve ().absolute ()
256267
257- file_path_to_qmd = Path (output_dir ) / f"{ self .BASE_DIR } .qmd"
268+ file_path_to_qmd = Path (self . output_dir ) / f"{ self .BASE_DIR } .qmd"
258269 args = [self .quarto_path , "render" , str (file_path_to_qmd )]
259270 self .report .logger .info (
260271 f"Running '{ self .report .title } ' '{ self .report_type } ' report with { args !r} "
@@ -554,13 +565,15 @@ def _generate_plot_content(self, plot) -> List[str]:
554565
555566 # Define plot path
556567 if self .is_report_static :
568+ # ? should that be in the output folder
557569 static_plot_path = (
558570 Path (self .static_dir ) / f"{ plot .title .replace (' ' , '_' )} .png"
559- )
571+ ).absolute ()
572+ self .report .logger .debug (f"Static plot path: { static_plot_path } " )
560573 else :
561574 html_plot_file = (
562575 Path (self .static_dir ) / f"{ plot .title .replace (' ' , '_' )} .html"
563- )
576+ ). absolute ()
564577
565578 # Add content for the different plot types
566579 try :
@@ -572,7 +585,7 @@ def _generate_plot_content(self, plot) -> List[str]:
572585 plot_content .append (self ._generate_plot_code (plot ))
573586 if self .is_report_static :
574587 plot_content .append (
575- f"""fig_plotly.write_image("{ static_plot_path .relative_to ("quarto_report" ).as_posix ()} ")\n ```\n """
588+ f"""fig_plotly.write_image("{ static_plot_path .relative_to (self . output_dir ).as_posix ()} ")\n ```\n """
576589 )
577590 plot_content .append (self ._generate_image_content (static_plot_path ))
578591 else :
@@ -581,7 +594,7 @@ def _generate_plot_content(self, plot) -> List[str]:
581594 plot_content .append (self ._generate_plot_code (plot ))
582595 if self .is_report_static :
583596 plot_content .append (
584- f"""fig_altair.save("{ static_plot_path .relative_to ( "quarto_report" ). as_posix ()} ")\n ```\n """
597+ f"""fig_altair.save("{ static_plot_path .as_posix ()} ")\n ```\n """
585598 )
586599 plot_content .append (self ._generate_image_content (static_plot_path ))
587600 else :
@@ -597,7 +610,7 @@ def _generate_plot_content(self, plot) -> List[str]:
597610 networkx_graph , html_plot_file
598611 )
599612
600- # Add number of nodes and edges to the plor conetnt
613+ # Add number of nodes and edges to the plot content
601614 num_nodes = networkx_graph .number_of_nodes ()
602615 num_edges = networkx_graph .number_of_edges ()
603616 plot_content .append (f"**Number of nodes:** { num_nodes } \n " )
@@ -653,9 +666,11 @@ def _generate_plot_code(self, plot, output_file="") -> str:
653666response.raise_for_status()
654667plot_json = response.text\n """
655668 else : # If it's a local file
656- plot_rel_path = get_relative_file_path (plot .file_path , base_path = ".." )
669+ plot_rel_path = get_relative_file_path (
670+ plot .file_path , relative_to = self .output_dir
671+ ).as_posix ()
657672 plot_code += f"""
658- with open('{ plot_rel_path . as_posix () } ', 'r') as plot_file:
673+ with open(report_dir / '{ plot_rel_path } ', 'r') as plot_file:
659674 plot_json = json.load(plot_file)\n """
660675 # Add specific code for each visualization tool
661676 if plot .plot_type == r .PlotType .PLOTLY :
@@ -680,7 +695,9 @@ def _generate_plot_code(self, plot, output_file="") -> str:
680695 if is_url (plot .file_path ) and plot .file_path .endswith (".html" ):
681696 iframe_src = output_file
682697 else :
683- iframe_src = Path (".." ) / output_file
698+ iframe_src = get_relative_file_path (
699+ output_file , relative_to = self .output_dir
700+ )
684701
685702 # Embed the HTML file in an iframe
686703 plot_code = f"""
@@ -757,12 +774,12 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
757774 df_file_path = dataframe .file_path
758775 else :
759776 df_file_path = get_relative_file_path (
760- dataframe .file_path , base_path = ".."
761- )
777+ dataframe .file_path , relative_to = self . output_dir
778+ ). as_posix ()
762779 # Load the DataFrame using the correct function
763780 read_function = read_function_mapping [file_extension ]
764781 dataframe_content .append (
765- f"""df = pd.{ read_function .__name__ } ('{ df_file_path . as_posix () } ')\n """
782+ f"""df = pd.{ read_function .__name__ } (report_dir / '{ df_file_path } ')\n """
766783 )
767784 # Display the dataframe
768785 dataframe_content .extend (self ._show_dataframe (dataframe ))
@@ -781,7 +798,7 @@ def _generate_dataframe_content(self, dataframe) -> List[str]:
781798 )
782799 )
783800 dataframe_content .append (
784- f"df = pd.{ read_function .__name__ } ('{ df_file_path . as_posix () } ', "
801+ f"df = pd.{ read_function .__name__ } (report_dir / '{ df_file_path } ', "
785802 f"sheet_name='{ sheet_name } ')\n "
786803 )
787804 # Display the dataframe
@@ -845,10 +862,12 @@ def _generate_markdown_content(self, markdown) -> List[str]:
845862 )
846863 )
847864 else : # If it's a local file
848- md_rel_path = get_relative_file_path (markdown .file_path , base_path = ".." )
865+ md_rel_path = get_relative_file_path (
866+ markdown .file_path , relative_to = self .output_dir
867+ )
849868 markdown_content .append (
850869 f"""
851- with open('{ md_rel_path .as_posix ()} ', 'r') as markdown_file:
870+ with open(report_dir / '{ md_rel_path .as_posix ()} ', 'r') as markdown_file:
852871 markdown_content = markdown_file.read()\n """
853872 )
854873
@@ -896,9 +915,11 @@ def _show_dataframe(self, dataframe, suffix: Optional[str] = None) -> List[str]:
896915 fpath_df_image .stem + f"_{ suffix .replace (' ' , '_' )} "
897916 )
898917 fpath_df_image = fpath_df_image .with_suffix (".png" )
899-
918+ fpath_df_image_rel_static = get_relative_file_path (
919+ fpath_df_image , relative_to = self .output_dir
920+ )
900921 dataframe_content .append (
901- f"df.dfi.export('{ Path ( fpath_df_image ). relative_to ( 'quarto_report' ). as_posix () } ',"
922+ f"df.dfi.export('{ fpath_df_image_rel_static } ',"
902923 " max_rows=10, max_cols=5, table_conversion='matplotlib')\n ```\n "
903924 )
904925 # Use helper method to add centered image content
@@ -935,7 +956,9 @@ def _generate_html_content(self, html) -> List[str]:
935956 if is_url (html .file_path ):
936957 html_file_path = html .file_path
937958 else :
938- html_file_path = get_relative_file_path (html .file_path , base_path = ".." )
959+ html_file_path = get_relative_file_path (
960+ html .file_path , relative_to = self .output_dir
961+ )
939962 iframe_code = f"""
940963<div style="text-align: center;">
941964<iframe src="{ html_file_path .as_posix ()} " alt="{ html .title } " width="950px" height="530px"></iframe>
@@ -978,7 +1001,9 @@ def _generate_image_content(
9781001 if is_url (image_path ):
9791002 src = image_path
9801003 else :
981- src = get_relative_file_path (image_path , base_path = ".." ).as_posix ()
1004+ src = get_relative_file_path (
1005+ image_path , relative_to = self .output_dir
1006+ ).as_posix ()
9821007
9831008 return f"""{{fig-alt={ alt_text } width={ width } }}\n """
9841009
0 commit comments