diff --git a/esmvalcore/_main.py b/esmvalcore/_main.py index 0488359ffe..96854d8aed 100755 --- a/esmvalcore/_main.py +++ b/esmvalcore/_main.py @@ -392,13 +392,28 @@ def run(self, self._run(recipe, session) + @staticmethod + def _create_session_dir(session): + """Create `session.session_dir` or an alternative if it exists.""" + from .exceptions import RecipeError + + session_dir = session.session_dir + for suffix in range(1, 1000): + try: + session_dir.mkdir(parents=True) + except FileExistsError: + session_dir = Path(f"{session.session_dir}-{suffix}") + else: + session.session_name = session_dir.name + return + + raise RecipeError( + f"Output directory '{session.session_dir}' already exists and" + " unable to find alternative, aborting to prevent data loss.") + def _run(self, recipe: Path, session) -> None: """Run `recipe` using `session`.""" - # Create run dir - if session.session_dir.exists(): - print(f"ERROR: output directory {session.session_dir} already" - " exists, aborting to prevent data loss") - session.session_dir.mkdir(parents=True) + self._create_session_dir(session) session.run_dir.mkdir() # configure logging diff --git a/tests/unit/main/test_esmvaltool.py b/tests/unit/main/test_esmvaltool.py index 08a9b15ab4..42aaabc4ec 100644 --- a/tests/unit/main/test_esmvaltool.py +++ b/tests/unit/main/test_esmvaltool.py @@ -12,6 +12,7 @@ import esmvalcore.esgf from esmvalcore import __version__ from esmvalcore._main import HEADER, ESMValTool +from esmvalcore.exceptions import RecipeError LOGGER = logging.getLogger(__name__) @@ -134,11 +135,23 @@ def test_run(mocker, session, offline): ) -def test_run_fail_session_dir_exists(session): +def test_run_session_dir_exists(session): program = ESMValTool() session.session_dir.mkdir(parents=True) - with pytest.raises(FileExistsError): - program._run(Path('/path/to/recipe_test.yml'), session) + session_dir = session.session_dir + program._create_session_dir(session) + assert session.session_name == f"{session_dir.name}-1" + + +def test_run_session_dir_exists_alternative_fails(mocker, session): + mocker.patch.object( + esmvalcore._main.Path, + 'mkdir', + side_effect=FileExistsError, + ) + program = ESMValTool() + with pytest.raises(RecipeError): + program._create_session_dir(session) def test_clean_preproc_dir(session):