-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add option to always keep temporary files (#199)
* Add option to always keep temporary files * Simplify tempcd * Specify type of BEFLOW_KEEP_TMP_FILES * Add tests for temporary_cd * Update temporary_cd to pass tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix test warnings * Add comment * Support multi-part paths without parents argument * Remove print statements from temporary_cd * Changes to optimizer worker to support KEEP_TMP_FILES * Try to keep QCEngine's scratch files * Deprecate BEFLOW_OPTIMIZER_KEEP_FILES * Revert "Try to keep QCEngine's scratch files" This reverts commit ff8dc2e. * Revert tests to use openff.utilities' temporary_cd * Consolidate various methods of deleting temporary files * Ensure deprecated alias of setting is unset in tests --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
- Loading branch information
1 parent
57f2ba4
commit 27813ab
Showing
8 changed files
with
218 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
from openff.bespokefit.utilities.tempcd import temporary_cd | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"path", | ||
[ | ||
"tempcd_test", | ||
"tempcd/test", | ||
Path("tempcd_test"), | ||
None, | ||
".", | ||
"", | ||
], | ||
) | ||
class TestTemporaryCD: | ||
@pytest.fixture(autouse=True) | ||
def run_test_in_empty_temporary_directory(self, monkeypatch, tmp_path): | ||
""" | ||
Tests in this class should run in their own empty temporary directories | ||
This fixture creates a temporary directory for the test, moves into it, | ||
and deletes it when the test is finished. | ||
""" | ||
monkeypatch.chdir(tmp_path) | ||
|
||
def test_tempcd_changes_dir(self, path): | ||
""" | ||
Check temporary_cd changes directory to the target directory | ||
""" | ||
# Arrange | ||
starting_path = Path(".").resolve() | ||
|
||
# Act | ||
with temporary_cd(path): | ||
temp_path = Path(".").resolve() | ||
|
||
# Assert | ||
if path is None: | ||
assert temp_path.parent == starting_path | ||
else: | ||
assert temp_path == (starting_path / path).resolve() | ||
|
||
def test_tempcd_changes_back(self, path): | ||
""" | ||
Check temporary_cd returns to original directory when context manager exits | ||
""" | ||
# Arrange | ||
starting_path = Path(".").resolve() | ||
|
||
# Act | ||
with temporary_cd(path): | ||
pass | ||
|
||
# Assert | ||
assert Path(".").resolve() == starting_path | ||
|
||
def test_tempcd_cleans_up_temporary_directory(self, path, monkeypatch): | ||
""" | ||
Check temporary_cd cleans up temporary directories it creates when | ||
BEFLOW_KEEP_TMP_FILES is not set | ||
This test is skipped when it is parametrized to operate on the working | ||
directory because the working directory must exist and therefore cannot | ||
be a temporary directory. This check is hard-coded to check for the | ||
path being ``"."`` or ``""``, rather than simply checking if the path | ||
exists, so that conflicts between runs will be detected (though such | ||
conflicts should be prevented by the | ||
``run_test_in_empty_temporary_directory`` fixture) | ||
""" | ||
if path in [".", ""]: | ||
pytest.skip("'Temporary' directory exists") | ||
|
||
# Arrange | ||
monkeypatch.delenv("BEFLOW_KEEP_TMP_FILES", raising=False) | ||
monkeypatch.delenv("BEFLOW_OPTIMIZER_KEEP_TMP_FILES", raising=False) | ||
|
||
# Act | ||
with temporary_cd(path): | ||
Path("touch").write_text("Ensure cleanup of directories with files") | ||
temp_path = Path(".").resolve() | ||
|
||
# Assert | ||
assert not temp_path.exists() | ||
|
||
def test_tempcd_keeps_temporary_directory(self, path, monkeypatch): | ||
""" | ||
Check temporary_cd keeps temporary directories it creates when | ||
BEFLOW_KEEP_TMP_FILES is set | ||
""" | ||
# Arrange | ||
monkeypatch.setenv("BEFLOW_KEEP_TMP_FILES", "1") | ||
monkeypatch.delenv("BEFLOW_OPTIMIZER_KEEP_TMP_FILES", raising=False) | ||
|
||
# Act | ||
with temporary_cd(path): | ||
temp_path = Path(".").resolve() | ||
|
||
# Assert | ||
assert temp_path.exists() | ||
|
||
@pytest.mark.parametrize("keep_tmp_files", [True, False]) | ||
def test_tempcd_keeps_existing_directory(self, path, monkeypatch, keep_tmp_files): | ||
""" | ||
Check temporary_cd keeps existing directories | ||
This test is skipped when the path is ``None`` because it guarantees | ||
that the path does not exist. The target directory will be created in | ||
the Arrange section, unless it is the working directory (in which case | ||
it already exists). This test is hard-coded to check for the path being | ||
``"."`` or ``""``, rather than simply checking if the path exists, so | ||
that conflicts between runs will be detected (though such conflicts | ||
should be prevented by the ``run_test_in_empty_temporary_directory`` | ||
fixture) | ||
""" | ||
if path is None: | ||
pytest.skip("Temporary directory is guaranteed not to exist") | ||
|
||
# Arrange | ||
if path not in [".", ""]: | ||
Path(path).mkdir(parents=True) | ||
if keep_tmp_files: | ||
monkeypatch.setenv("BEFLOW_KEEP_TMP_FILES", "1") | ||
else: | ||
monkeypatch.delenv("BEFLOW_KEEP_TMP_FILES", raising=False) | ||
monkeypatch.delenv("BEFLOW_OPTIMIZER_KEEP_TMP_FILES", raising=False) | ||
|
||
# Act | ||
with temporary_cd(path): | ||
pass | ||
|
||
# Assert | ||
assert Path(path).is_dir() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
"""""" | ||
import os | ||
import shutil | ||
import tempfile | ||
from contextlib import contextmanager | ||
from pathlib import Path | ||
from typing import Optional, Union | ||
|
||
from openff.bespokefit.executor.services import current_settings | ||
|
||
|
||
@contextmanager | ||
def temporary_cd(path: Optional[Union[str, Path]] = None): | ||
""" | ||
Context manager to move the current working directory to the path specified. | ||
If no path is given or the path does not exist, a temporary directory will | ||
be created. This temporary directory and its contents will be deleted when | ||
the context manager exits. | ||
Parameters | ||
---------- | ||
path | ||
The path to CD into. If ``None`` or not specified, a temporary directory | ||
will be created. If specified but the path does not exist, a temporary | ||
directory with that name will be created. | ||
""" | ||
# Normalize path to a pathlib Path | ||
path: Optional[Path] = None if path is None else Path(path) | ||
|
||
# Decide whether to clean up based on bespokefit settings | ||
settings = current_settings() | ||
cleanup = not ( | ||
settings.BEFLOW_OPTIMIZER_KEEP_FILES or settings.BEFLOW_KEEP_TMP_FILES | ||
) | ||
|
||
# If a path is not given, create a temporary directory | ||
if path is None: | ||
path = Path(tempfile.mkdtemp(dir=".")) | ||
# If a path is given but does not already exist, create it | ||
elif not path.exists(): | ||
path.mkdir(parents=True) | ||
# If we didn't create the path, do NOT clean it up | ||
else: | ||
cleanup = False | ||
|
||
old_directory = os.getcwd() | ||
|
||
try: | ||
os.chdir(path) | ||
yield | ||
|
||
finally: | ||
os.chdir(old_directory) | ||
# If we created the directory, clean it up | ||
if cleanup: | ||
print(f"cleaning up temporary directory {path}") | ||
shutil.rmtree(path) |