From acab5e5d622feb54f689237928e87c8131de0a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20K=C3=B6ster?= Date: Thu, 25 Nov 2021 15:44:59 +0100 Subject: [PATCH 1/2] fix: provide temporary IPYTHONDIR for notebook execution in order to avoid race conditions in https://github.com/ipython/ipython/blob/master/IPython/paths.py#L20 upon execution of multiple notebooks at the same time. --- snakemake/notebook.py | 54 ++++++++++++++++++++++++------------------- snakemake/shell.py | 11 +++++++++ 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/snakemake/notebook.py b/snakemake/notebook.py index 5cf4a8143..02bb70403 100644 --- a/snakemake/notebook.py +++ b/snakemake/notebook.py @@ -71,37 +71,43 @@ def execute_script(self, fname, edit=None): fname_out = os.path.join(os.getcwd(), fname_out) output_parameter = "--output {fname_out:q}" - if edit is not None: - logger.info("Opening notebook for editing.") - cmd = ( - "jupyter notebook --browser ':' --no-browser --log-level ERROR --ip {edit.ip} --port {edit.port} " - "--NotebookApp.quit_button=True {{fname:q}}".format(edit=edit) - ) - else: - cmd = ( - "jupyter-nbconvert --log-level ERROR --execute {output_parameter} " - "--to notebook --ExecutePreprocessor.timeout=-1 {{fname:q}}".format( - output_parameter=output_parameter + with tempfile.TemporaryDirectory() as tmp: + if edit is not None: + logger.info("Opening notebook for editing.") + cmd = ( + "jupyter notebook --browser ':' --no-browser --log-level ERROR --ip {edit.ip} --port {edit.port} " + "--NotebookApp.quit_button=True {{fname:q}}".format(edit=edit) + ) + else: + cmd = ( + "jupyter-nbconvert --log-level ERROR --execute {output_parameter} " + "--to notebook --ExecutePreprocessor.timeout=-1 {{fname:q}}".format( + output_parameter=output_parameter, + ) ) - ) - if ON_WINDOWS: - fname = fname.replace("\\", "/") - fname_out = fname_out.replace("\\", "/") if fname_out else fname_out + if ON_WINDOWS: + fname = fname.replace("\\", "/") + fname_out = fname_out.replace("\\", "/") if fname_out else fname_out - self._execute_cmd(cmd, fname_out=fname_out, fname=fname) + self._execute_cmd( + cmd, + fname_out=fname_out, + fname=fname, + additional_envvars={"IPYTHONDIR": tmp.name}, + ) - if edit: - logger.info("Saving modified notebook.") - nb = nbformat.read(fname, as_version=4) + if edit: + logger.info("Saving modified notebook.") + nb = nbformat.read(fname, as_version=4) - self.remove_preamble_cell(nb) + self.remove_preamble_cell(nb) - # clean up all outputs - for cell in nb["cells"]: - cell["outputs"] = [] + # clean up all outputs + for cell in nb["cells"]: + cell["outputs"] = [] - nbformat.write(nb, self.local_path) + nbformat.write(nb, self.local_path) def insert_preamble_cell(self, preamble, notebook): import nbformat diff --git a/snakemake/shell.py b/snakemake/shell.py index ea75cd411..860fecc07 100644 --- a/snakemake/shell.py +++ b/snakemake/shell.py @@ -219,6 +219,17 @@ def __new__( envvars["TEMPDIR"] = tmpdir_resource envvars["TEMP"] = tmpdir_resource + if "additional_envvars" in kwargs: + env = kwargs["additional_envvars"] + if not isinstance(env, dict) or not all( + isinstance(v, str) for v in env.values() + ): + raise WorkflowError( + "Given environment variables for shell command have to be a dict of strings, " + "but the following was provided instead:\n{}".format(env) + ) + envvars.update(env) + if conda_env and cls.conda_block_conflicting_envvars: # remove envvars that conflict with conda for var in ["R_LIBS", "PYTHONPATH", "PERLLIB", "PERL5LIB"]: From 895b989fe33a941ec607ff1f7c68d3b1528006e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20K=C3=B6ster?= Date: Fri, 26 Nov 2021 10:24:26 +0100 Subject: [PATCH 2/2] fix tmpdir usage --- snakemake/notebook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snakemake/notebook.py b/snakemake/notebook.py index 02bb70403..fa7768db9 100644 --- a/snakemake/notebook.py +++ b/snakemake/notebook.py @@ -94,7 +94,7 @@ def execute_script(self, fname, edit=None): cmd, fname_out=fname_out, fname=fname, - additional_envvars={"IPYTHONDIR": tmp.name}, + additional_envvars={"IPYTHONDIR": tmp}, ) if edit: