From 7250ced981f2d19ab6001382075565775cd97466 Mon Sep 17 00:00:00 2001 From: GeorgWa Date: Mon, 10 Jun 2024 18:03:58 -0400 Subject: [PATCH 1/5] use parquet as intermediate output --- alphadia/outputaccumulator.py | 4 ++-- alphadia/outputtransform.py | 16 ++++------------ alphadia/planning.py | 8 ++++---- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/alphadia/outputaccumulator.py b/alphadia/outputaccumulator.py index 5328acab..f9465711 100644 --- a/alphadia/outputaccumulator.py +++ b/alphadia/outputaccumulator.py @@ -122,8 +122,8 @@ def parse_output_folder( """ - psm_df = pd.read_csv(os.path.join(folder, "psm.tsv"), sep="\t") - frag_df = pd.read_csv(os.path.join(folder, "frag.tsv"), sep="\t") + psm_df = pd.read_parquet(os.path.join(folder, "psm.parquet")) + frag_df = pd.read_parquet(os.path.join(folder, "frag.parquet")) assert set( selected_precursor_columns diff --git a/alphadia/outputtransform.py b/alphadia/outputtransform.py index b62dc1cf..9276cff7 100644 --- a/alphadia/outputtransform.py +++ b/alphadia/outputtransform.py @@ -54,22 +54,14 @@ def get_frag_df_generator(folder_list: List[str]): for folder in folder_list: raw_name = os.path.basename(folder) - frag_path = os.path.join(folder, "frag.tsv") + frag_path = os.path.join(folder, "frag.parquet") if not os.path.exists(frag_path): logger.warning(f"no frag file found for {raw_name}") else: try: logger.info(f"reading frag file for {raw_name}") - run_df = pd.read_csv( - frag_path, - sep="\t", - dtype={ - "precursor_idx": np.uint32, - "number": np.uint8, - "type": np.uint8, - }, - ) + run_df = pd.read_parquet(frag_path) except Exception as e: logger.warning(f"Error reading frag file for {raw_name}") logger.warning(e) @@ -497,7 +489,7 @@ def build_precursor_table( for folder in folder_list: raw_name = os.path.basename(folder) - psm_path = os.path.join(folder, f"{self.PSM_INPUT}.tsv") + psm_path = os.path.join(folder, f"{self.PSM_INPUT}.parquet") logger.info(f"Building output for {raw_name}") @@ -506,7 +498,7 @@ def build_precursor_table( run_df = pd.DataFrame() else: try: - run_df = pd.read_csv(psm_path, sep="\t") + run_df = pd.read_parquet(psm_path) except Exception as e: logger.warning(f"Error reading psm file for {raw_name}") logger.warning(e) diff --git a/alphadia/planning.py b/alphadia/planning.py index 784028ff..f9fe1292 100644 --- a/alphadia/planning.py +++ b/alphadia/planning.py @@ -283,8 +283,8 @@ def run( workflow_folder_list.append(workflow.path) # check if the raw file is already processed - psm_location = os.path.join(workflow.path, "psm.tsv") - frag_location = os.path.join(workflow.path, "frag.tsv") + psm_location = os.path.join(workflow.path, "psm.parquet") + frag_location = os.path.join(workflow.path, "frag.parquet") if self.config["general"]["reuse_quant"]: if os.path.exists(psm_location) and os.path.exists(frag_location): @@ -306,8 +306,8 @@ def run( psm_df, frag_df = workflow.requantify_fragments(psm_df) psm_df["run"] = raw_name - psm_df.to_csv(psm_location, sep="\t", index=False) - frag_df.to_csv(frag_location, sep="\t", index=False) + psm_df.to_parquet(psm_location, index=False) + frag_df.to_parquet(frag_location, index=False) workflow.reporter.log_string(f"Finished workflow for {raw_name}") workflow.reporter.context.__exit__(None, None, None) From 64c9c94dcae5e47f2add19eea6e58fb001920b22 Mon Sep 17 00:00:00 2001 From: GeorgWa Date: Mon, 10 Jun 2024 19:14:53 -0400 Subject: [PATCH 2/5] universal read write --- alphadia/consensus/utils.py | 84 ++++++++++++++++++++++++++++++ alphadia/constants/default.yaml | 2 + alphadia/outputtransform.py | 16 ++---- alphadia/peakgroup/search.py | 2 +- tests/unit_tests/conftest.py | 12 +++++ tests/unit_tests/test_consensus.py | 25 +++++++++ 6 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 alphadia/consensus/utils.py create mode 100644 tests/unit_tests/test_consensus.py diff --git a/alphadia/consensus/utils.py b/alphadia/consensus/utils.py new file mode 100644 index 00000000..71054635 --- /dev/null +++ b/alphadia/consensus/utils.py @@ -0,0 +1,84 @@ +import logging +import os +import pandas as pd + +logger = logging.getLogger() +supported_formats = ["parquet", "tsv"] + + +def read_df(path_no_format, file_format="parquet"): + """Read dataframe from disk with choosen file format + + Parameters + ---------- + + path_no_format: str + File to read from disk without file format + + file_format: str, default = 'parquet' + File format for loading the file. Available options: ['parquet', 'tsv'] + + Returns + ------- + + pd.DataFrame + loaded dataframe from disk + + """ + + if file_format not in supported_formats: + raise ValueError( + f"Provided unknown file format: {file_format}, supported_formats: {supported_formats}" + ) + + file_path = f"{path_no_format}.{file_format}" + + if not os.path.exists(file_path): + raise FileNotFoundError(f"Can't load file as file was not found: {file_path}") + + logger.info(f"Reading {file_path} from disk") + + if file_format == "parquet": + return pd.read_parquet(file_path) + + elif file_format == "tsv": + return pd.read_csv(file_path, sep="\t") + + else: + raise ValueError("I don't know how you ended up here") + + +def write_df(df, path_no_format, file_format="parquet"): + """Read dataframe from disk with choosen file format + + Parameters + ---------- + + df: pd.DataFrame + Dataframe to save to disk + + path_no_format: str + Path for file without format + + file_format: str, default = 'parquet' + File format for loading the file. Available options: ['parquet', 'tsv'] + + """ + + if file_format not in supported_formats: + raise ValueError( + f"Provided unknown file format: {file_format}, supported_formats: {supported_formats}" + ) + + file_path = f"{path_no_format}.{file_format}" + + logger.info(f"Saving {file_path} to disk") + + if file_format == "parquet": + df.to_parquet(file_path, index=False) + + elif file_format == "tsv": + df.to_csv(file_path, sep="\t", index=False) + + else: + raise ValueError("I don't know how you ended up here") diff --git a/alphadia/constants/default.yaml b/alphadia/constants/default.yaml index 5339a3df..4833a500 100644 --- a/alphadia/constants/default.yaml +++ b/alphadia/constants/default.yaml @@ -129,6 +129,8 @@ search_output: num_samples_quadratic: 50 min_nonnan: 3 normalize_lfq: True + # can be either "parquet" or "tsv" + file_format: "parquet" # configuration for the optimization manager # initial parameters, will nbe optimized diff --git a/alphadia/outputtransform.py b/alphadia/outputtransform.py index 9276cff7..c8ce6985 100644 --- a/alphadia/outputtransform.py +++ b/alphadia/outputtransform.py @@ -445,20 +445,10 @@ def load_precursor_table(self): Precursor table """ - if not os.path.exists( - os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}.tsv") - ): - logger.error( - f"Can't continue as no {self.PRECURSOR_OUTPUT}.tsv file was found in the output folder: {self.output_folder}" - ) - raise FileNotFoundError( - f"Can't continue as no {self.PRECURSOR_OUTPUT}.tsv file was found in the output folder: {self.output_folder}" - ) - logger.info(f"Reading {self.PRECURSOR_OUTPUT}.tsv file") - psm_df = pd.read_csv( - os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}.tsv"), sep="\t" + return read_df( + os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}"), + file_type=self.config["file_format"], ) - return psm_df def build_precursor_table( self, diff --git a/alphadia/peakgroup/search.py b/alphadia/peakgroup/search.py index 0b97d445..9f3f6a42 100644 --- a/alphadia/peakgroup/search.py +++ b/alphadia/peakgroup/search.py @@ -1041,7 +1041,7 @@ def assemble_candidates(self, elution_group_container): precursor_flat_lookup ] - # save features for training if desired. + # DEBUG: save features for training if desired. if self.feature_path is not None: feature_matrix = np.zeros( (len(candidates), len(candidates[0].features)), dtype=np.float32 diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index b1a90b82..1976b9d7 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -4,6 +4,7 @@ import pandas as pd import numpy as np import matplotlib +import tempfile matplotlib.use("Agg") from matplotlib import pyplot as plt @@ -184,3 +185,14 @@ def pytest_configure(config): pytest.test_data[raw_folder] = raw_files # important to supress matplotlib output + + +def _random_tempfolder(): + tempdir = tempfile.gettempdir() + # 6 alphanumeric characters + random_foldername = "alphadia_" + "".join( + np.random.choice(list("abcdefghijklmnopqrstuvwxyz0123456789"), 6) + ) + path = os.path.join(tempdir, random_foldername) + os.mkdir(path) + return path diff --git a/tests/unit_tests/test_consensus.py b/tests/unit_tests/test_consensus.py new file mode 100644 index 00000000..f592e4ee --- /dev/null +++ b/tests/unit_tests/test_consensus.py @@ -0,0 +1,25 @@ +import pytest +import pandas as pd +import os +from conftest import _random_tempfolder +from alphadia.consensus.utils import read_df, write_df + + +@pytest.mark.parametrize( + "format, should_fail", + [("tsv", False), ("parquet", False), ("a321", True)], +) +def test_read_write(format, should_fail): + # given + df = pd.DataFrame([{"a": "a", "b": "b"}, {"a": "a", "b": "b"}]) + path = os.path.join(_random_tempfolder()) + + # when + if should_fail: + with pytest.raises(ValueError): + write_df(df, path, file_format=format) + + else: + write_df(df, path, file_format=format) + _df = read_df(path, file_format=format) + assert df.equals(_df) From 7876db62e3cc68bccb87775e8d1b082f0360ce1f Mon Sep 17 00:00:00 2001 From: GeorgWa Date: Mon, 10 Jun 2024 19:37:12 -0400 Subject: [PATCH 3/5] variable output format --- alphadia/consensus/utils.py | 2 +- alphadia/outputtransform.py | 39 +++++++++++++++++-------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/alphadia/consensus/utils.py b/alphadia/consensus/utils.py index 71054635..07638fb6 100644 --- a/alphadia/consensus/utils.py +++ b/alphadia/consensus/utils.py @@ -78,7 +78,7 @@ def write_df(df, path_no_format, file_format="parquet"): df.to_parquet(file_path, index=False) elif file_format == "tsv": - df.to_csv(file_path, sep="\t", index=False) + df.to_csv(file_path, sep="\t", index=False, float_format="%.6f") else: raise ValueError("I don't know how you ended up here") diff --git a/alphadia/outputtransform.py b/alphadia/outputtransform.py index c8ce6985..9f1746d6 100644 --- a/alphadia/outputtransform.py +++ b/alphadia/outputtransform.py @@ -10,7 +10,7 @@ TransferLearningAccumulator, AccumulationBroadcaster, ) - +from alphadia.consensus.utils import read_df, write_df import pandas as pd import numpy as np @@ -578,11 +578,10 @@ def build_precursor_table( psm_df = psm_df[psm_df["decoy"] == 0] if save: logger.info("Writing precursor output to disk") - psm_df.to_csv( - os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}.tsv"), - sep="\t", - index=False, - float_format="%.6f", + write_df( + psm_df, + os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}"), + file_format=self.config["search_output"]["file_format"], ) return psm_df @@ -630,11 +629,10 @@ def build_stat_df( if save: logger.info("Writing stat output to disk") - stat_df.to_csv( - os.path.join(self.output_folder, f"{self.STAT_OUTPUT}.tsv"), - sep="\t", - index=False, - float_format="%.6f", + write_df( + stat_df, + os.path.join(self.output_folder, f"{self.STAT_OUTPUT}"), + file_format="tsv", ) return stat_df @@ -712,11 +710,11 @@ def build_lfq_tables( if save: logger.info(f"Writing {group_nice} output to disk") - lfq_df.to_csv( - os.path.join(self.output_folder, f"{group_nice}.matrix.tsv"), - sep="\t", - index=False, - float_format="%.6f", + + write_df( + lfq_df, + os.path.join(self.output_folder, f"{group_nice}.matrix"), + file_format=self.config["search_output"]["file_format"], ) protein_df_melted = lfq_df.melt( @@ -727,11 +725,10 @@ def build_lfq_tables( if save: logger.info("Writing psm output to disk") - psm_df.to_csv( - os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}.tsv"), - sep="\t", - index=False, - float_format="%.6f", + write_df( + psm_df, + os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}"), + file_format=self.config["search_output"]["file_format"], ) return lfq_df From 74bb3621a3817eba07200843dbb76b77a3669f61 Mon Sep 17 00:00:00 2001 From: GeorgWa Date: Mon, 10 Jun 2024 19:58:58 -0400 Subject: [PATCH 4/5] fix tests --- alphadia/outputtransform.py | 2 +- tests/unit_tests/conftest.py | 4 ++-- tests/unit_tests/test_consensus.py | 4 ++-- tests/unit_tests/test_outputaccumulator.py | 6 +++--- tests/unit_tests/test_outputtransform.py | 11 ++++++----- tests/unit_tests/test_reporting.py | 23 +++++++--------------- 6 files changed, 21 insertions(+), 29 deletions(-) diff --git a/alphadia/outputtransform.py b/alphadia/outputtransform.py index 9f1746d6..75a0db4b 100644 --- a/alphadia/outputtransform.py +++ b/alphadia/outputtransform.py @@ -447,7 +447,7 @@ def load_precursor_table(self): return read_df( os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}"), - file_type=self.config["file_format"], + file_format=self.config["search_output"]["file_format"], ) def build_precursor_table( diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 1976b9d7..5f977eb9 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -187,12 +187,12 @@ def pytest_configure(config): # important to supress matplotlib output -def _random_tempfolder(): +def random_tempfolder(): tempdir = tempfile.gettempdir() # 6 alphanumeric characters random_foldername = "alphadia_" + "".join( np.random.choice(list("abcdefghijklmnopqrstuvwxyz0123456789"), 6) ) path = os.path.join(tempdir, random_foldername) - os.mkdir(path) + os.makedirs(path, exist_ok=True) return path diff --git a/tests/unit_tests/test_consensus.py b/tests/unit_tests/test_consensus.py index f592e4ee..65aa5b19 100644 --- a/tests/unit_tests/test_consensus.py +++ b/tests/unit_tests/test_consensus.py @@ -1,7 +1,7 @@ import pytest import pandas as pd import os -from conftest import _random_tempfolder +from conftest import random_tempfolder from alphadia.consensus.utils import read_df, write_df @@ -12,7 +12,7 @@ def test_read_write(format, should_fail): # given df = pd.DataFrame([{"a": "a", "b": "b"}, {"a": "a", "b": "b"}]) - path = os.path.join(_random_tempfolder()) + path = os.path.join(random_tempfolder()) # when if should_fail: diff --git a/tests/unit_tests/test_outputaccumulator.py b/tests/unit_tests/test_outputaccumulator.py index 097e59f5..9de649b4 100644 --- a/tests/unit_tests/test_outputaccumulator.py +++ b/tests/unit_tests/test_outputaccumulator.py @@ -98,9 +98,9 @@ def prepare_input_data(): for i, raw_folder in enumerate(raw_folders): os.makedirs(raw_folder, exist_ok=True) - psm_dfs[i].to_csv(os.path.join(raw_folder, "psm.tsv"), sep="\t", index=False) - fragment_dfs[i].to_csv( - os.path.join(raw_folder, "frag.tsv"), sep="\t", index=False + psm_dfs[i].to_parquet(os.path.join(raw_folder, "psm.parquet"), index=False) + fragment_dfs[i].to_parquet( + os.path.join(raw_folder, "frag.parquet"), index=False ) return config, temp_folder, raw_folders, psm_dfs, fragment_dfs diff --git a/tests/unit_tests/test_outputtransform.py b/tests/unit_tests/test_outputtransform.py index 91a18926..bdbe038a 100644 --- a/tests/unit_tests/test_outputtransform.py +++ b/tests/unit_tests/test_outputtransform.py @@ -28,6 +28,7 @@ def test_output_transform(): "normalize_lfq": True, "peptide_level_lfq": False, "precursor_level_lfq": False, + "file_format": "parquet", }, } @@ -52,8 +53,8 @@ def test_output_transform(): fragment_base_df["precursor_idx"].isin(psm_df["precursor_idx"]) ] - frag_df.to_csv(os.path.join(raw_folder, "frag.tsv"), sep="\t", index=False) - psm_df.to_csv(os.path.join(raw_folder, "psm.tsv"), sep="\t", index=False) + frag_df.to_parquet(os.path.join(raw_folder, "frag.parquet"), index=False) + psm_df.to_parquet(os.path.join(raw_folder, "psm.parquet"), index=False) output = outputtransform.SearchPlanOutput(config, temp_folder) _ = output.build_precursor_table(raw_folders, save=True) @@ -61,8 +62,8 @@ def test_output_transform(): _ = output.build_lfq_tables(raw_folders, save=True) # validate psm_df output - psm_df = pd.read_csv( - os.path.join(temp_folder, f"{output.PRECURSOR_OUTPUT}.tsv"), sep="\t" + psm_df = pd.read_parquet( + os.path.join(temp_folder, f"{output.PRECURSOR_OUTPUT}.parquet"), ) assert all( [ @@ -91,7 +92,7 @@ def test_output_transform(): assert all([col in stat_df.columns for col in ["run", "precursors", "proteins"]]) # validate protein_df output - protein_df = pd.read_csv(os.path.join(temp_folder, "pg.matrix.tsv"), sep="\t") + protein_df = pd.read_parquet(os.path.join(temp_folder, "pg.matrix.parquet")) assert all([col in protein_df.columns for col in ["run_0", "run_1", "run_2"]]) for i in run_columns: diff --git a/tests/unit_tests/test_reporting.py b/tests/unit_tests/test_reporting.py index ed536de0..5d171f74 100644 --- a/tests/unit_tests/test_reporting.py +++ b/tests/unit_tests/test_reporting.py @@ -7,23 +7,14 @@ import sys import pytest -from alphadia.workflow import reporting - +from conftest import random_tempfolder -def _random_tempfolder(): - tempdir = tempfile.gettempdir() - # 6 alphanumeric characters - random_foldername = "".join( - np.random.choice(list("abcdefghijklmnopqrstuvwxyz0123456789"), 6) - ) - path = os.path.join(tempdir, random_foldername) - os.mkdir(path) - return path +from alphadia.workflow import reporting @pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") def test_logging(): - tempfolder = _random_tempfolder() + tempfolder = random_tempfolder() if os.path.exists(os.path.join(tempfolder, "log.txt")): os.remove(os.path.join(tempfolder, "log.txt")) @@ -58,7 +49,7 @@ def test_backend(): def test_figure_backend(): - tempfolder = _random_tempfolder() + tempfolder = random_tempfolder() figure_backend = reporting.FigureBackend(path=tempfolder) @@ -79,7 +70,7 @@ def test_figure_backend(): def test_jsonl_backend(): - tempfolder = _random_tempfolder() + tempfolder = random_tempfolder() with reporting.JSONLBackend(path=tempfolder) as jsonl_backend: jsonl_backend.log_event("start_extraction", None) @@ -96,7 +87,7 @@ def test_jsonl_backend(): @pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") def test_log_backend(): - tempfolder = _random_tempfolder() + tempfolder = random_tempfolder() if os.path.exists(os.path.join(tempfolder, "log.txt")): os.remove(os.path.join(tempfolder, "log.txt")) @@ -117,7 +108,7 @@ def test_log_backend(): @pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") def test_pipeline(): - tempfolder = _random_tempfolder() + tempfolder = random_tempfolder() pipeline = reporting.Pipeline( backends=[ From db1e3f4c8cae05085f52ac9c43e0f6818c8b9025 Mon Sep 17 00:00:00 2001 From: GeorgWa Date: Wed, 12 Jun 2024 18:03:53 -0700 Subject: [PATCH 5/5] implement fixes --- alphadia/consensus/utils.py | 9 +++------ alphadia/constants/default.yaml | 2 +- alphadia/outputtransform.py | 4 ++-- tests/unit_tests/conftest.py | 12 ++++++++++++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/alphadia/consensus/utils.py b/alphadia/consensus/utils.py index 07638fb6..084ded8d 100644 --- a/alphadia/consensus/utils.py +++ b/alphadia/consensus/utils.py @@ -26,11 +26,6 @@ def read_df(path_no_format, file_format="parquet"): """ - if file_format not in supported_formats: - raise ValueError( - f"Provided unknown file format: {file_format}, supported_formats: {supported_formats}" - ) - file_path = f"{path_no_format}.{file_format}" if not os.path.exists(file_path): @@ -45,7 +40,9 @@ def read_df(path_no_format, file_format="parquet"): return pd.read_csv(file_path, sep="\t") else: - raise ValueError("I don't know how you ended up here") + raise ValueError( + f"Provided unknown file format: {file_format}, supported_formats: {supported_formats}" + ) def write_df(df, path_no_format, file_format="parquet"): diff --git a/alphadia/constants/default.yaml b/alphadia/constants/default.yaml index 4833a500..3d3a8112 100644 --- a/alphadia/constants/default.yaml +++ b/alphadia/constants/default.yaml @@ -130,7 +130,7 @@ search_output: min_nonnan: 3 normalize_lfq: True # can be either "parquet" or "tsv" - file_format: "parquet" + file_format: "tsv" # configuration for the optimization manager # initial parameters, will nbe optimized diff --git a/alphadia/outputtransform.py b/alphadia/outputtransform.py index 75a0db4b..f5db4491 100644 --- a/alphadia/outputtransform.py +++ b/alphadia/outputtransform.py @@ -580,7 +580,7 @@ def build_precursor_table( logger.info("Writing precursor output to disk") write_df( psm_df, - os.path.join(self.output_folder, f"{self.PRECURSOR_OUTPUT}"), + os.path.join(self.output_folder, self.PRECURSOR_OUTPUT), file_format=self.config["search_output"]["file_format"], ) @@ -631,7 +631,7 @@ def build_stat_df( logger.info("Writing stat output to disk") write_df( stat_df, - os.path.join(self.output_folder, f"{self.STAT_OUTPUT}"), + os.path.join(self.output_folder, self.STAT_OUTPUT), file_format="tsv", ) diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 5f977eb9..3ddd2017 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -24,6 +24,9 @@ def mock_precursor_df( n_precursor : int Number of precursors to generate + with_decoy : bool + If True, half of the precursors will be decoys + Returns ------- @@ -188,6 +191,14 @@ def pytest_configure(config): def random_tempfolder(): + """Create a randomly named temp folder in the system temp folder + + Returns + ------- + path : str + Path to the created temp folder + + """ tempdir = tempfile.gettempdir() # 6 alphanumeric characters random_foldername = "alphadia_" + "".join( @@ -195,4 +206,5 @@ def random_tempfolder(): ) path = os.path.join(tempdir, random_foldername) os.makedirs(path, exist_ok=True) + print(f"Created temp folder: {path}") return path