diff --git a/cluster_utils/job.py b/cluster_utils/job.py index f0de4ca..90e579e 100644 --- a/cluster_utils/job.py +++ b/cluster_utils/job.py @@ -4,9 +4,8 @@ import os import pathlib import time -import typing from copy import deepcopy -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any, Dict, Optional, Union import pandas as pd @@ -103,15 +102,19 @@ def generate_execution_cmd(self, paths, cmd_prefix: Optional[str] = None): set_cwd = "cd {}".format(paths["main_path"]) if "variables" in paths: - if not isinstance(paths, dict): + if not isinstance(paths["variables"], dict): raise ValueError( 'Expected type dict for "variables", but got type' f' {type(paths["variables"])} instead' ) + env_variables = { + str(name): str(value) for name, value in paths["variables"].items() + } set_env_variables = "\n".join( - f"export {name}={value}" for name, value in paths["variables"].items() + f'export {name}="{value}"' for name, value in env_variables.items() ) else: + env_variables = None set_env_variables = "" if "pre_job_script" in paths: @@ -181,6 +184,7 @@ def generate_execution_cmd(self, paths, cmd_prefix: Optional[str] = None): self.singularity_settings, paths["main_path"], current_setting["working_dir"], + env_variables, ) if cmd_prefix: @@ -189,10 +193,10 @@ def generate_execution_cmd(self, paths, cmd_prefix: Optional[str] = None): res = "\n".join( [ set_cwd, - pre_job_script, virtual_env_activate, conda_env_activate, set_env_variables, + pre_job_script, exec_cmd, ] ) @@ -202,8 +206,9 @@ def singularity_wrap( self, exec_cmd: str, singularity_settings: SingularitySettings, - exec_dir: typing.Union[str, os.PathLike], - working_dir: typing.Union[str, os.PathLike], + exec_dir: Union[str, os.PathLike], + working_dir: Union[str, os.PathLike], + env_variables: Optional[Dict[str, str]], ) -> str: """Wrap the given command to execute it in a Singularity container. @@ -223,6 +228,9 @@ def singularity_wrap( # create model directory (so it can be bound into the container) working_dir.mkdir(exist_ok=True) + if env_variables is None: + env_variables = {} + # construct singularity command cwd = os.fspath(exec_dir) bind_dirs = ["/tmp", os.fspath(working_dir), cwd] @@ -231,6 +239,9 @@ def singularity_wrap( "run" if singularity_settings.use_run else "exec", "--bind=%s" % ",".join(bind_dirs), "--pwd=%s" % cwd, + " ".join( + f'--env {name}="{value}"' for name, value in env_variables.items() + ), *singularity_settings.args, os.fspath(singularity_image), ] diff --git a/docs/configuration.rst b/docs/configuration.rst index a6d816b..dd15ed7 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -134,8 +134,11 @@ These parameters are the same for ``grid_search`` and ``hp_optimization``. .. confval:: environment_setup.variables: dict[str]: - Environment variables to set. Variables are set after a virtual/conda - environment is activated, thus override environment variables set before. + Environment variables to set. Variables are set *after* a virtual/conda environment + is activated, thus override environment variables set before. They are also set + *before* the :confval:`environment_setup.pre_job_script`: this can be useful to pass + parameters to the script, e.g. to setup a generic script that changes its behavior based + on the values defined in the cluster_utils config file. .. confval:: environment_setup.is_python_script: bool, default=true: @@ -408,7 +411,7 @@ Specific for hp_optimization **Required.** The optimisation method that is used to find good hyperparameters. - Supported methods are + Supported methods are - cem_metaoptimizer - nevergrad \* @@ -452,7 +455,7 @@ Specific for hp_optimization * - IntNormal - Normal distribution using integer values. * - IntLogNormal - - Log-normal distribution using integer values. + - Log-normal distribution using integer values. * - Discrete - Discrete list of values. - ``bounds``: List ``[min_value, max_value]``