diff --git a/pre_commit/languages/conda.py b/pre_commit/languages/conda.py index fe17a2d0..c258736c 100644 --- a/pre_commit/languages/conda.py +++ b/pre_commit/languages/conda.py @@ -67,6 +67,7 @@ def install_environment( with open(env_yaml_path) as env_file: env_yaml = yaml_load(env_file) env_yaml['dependencies'] += additional_dependencies + tmp_env_file = None try: with NamedTemporaryFile( suffix='.yml', @@ -80,7 +81,7 @@ def install_environment( tmp_env_file.name, cwd=prefix.prefix_dir, ) finally: - if os.path.exists(tmp_env_file.name): + if tmp_env_file and os.path.exists(tmp_env_file.name): os.remove(tmp_env_file.name) diff --git a/tests/repository_test.py b/tests/repository_test.py index d513cb71..9664437f 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1,6 +1,7 @@ import os.path import shutil import sys +from tempfile import NamedTemporaryFile from typing import Any from typing import Dict from unittest import mock @@ -87,7 +88,19 @@ def test_conda_hook(tempdir_factory, store): ) -def test_conda_with_additional_dependencies_hook(tempdir_factory, store): +def test_conda_with_additional_dependencies_hook( + tempdir_factory, store, monkeypatch, +): + remove = mock.Mock() + monkeypatch.setattr('pre_commit.languages.conda.os.remove', remove) + temp_file = NamedTemporaryFile(mode='w', suffix='.yml', delete=False) + + def named_tmp_file_mock(**kwargs): + return temp_file + monkeypatch.setattr( + 'pre_commit.languages.conda.NamedTemporaryFile', + named_tmp_file_mock, + ) _test_hook_repo( tempdir_factory, store, 'conda_hooks_repo', 'additional-deps', [os.devnull], @@ -101,6 +114,39 @@ def test_conda_with_additional_dependencies_hook(tempdir_factory, store): }, ) + # check proper tmp_env.yml removal + remove.assert_called_once_with(temp_file.name) + os.remove(temp_file.name) + + +def test_conda_tmp_file_fail(tempdir_factory, store, monkeypatch): + temp_file = NamedTemporaryFile(mode='w', suffix='.yml', delete=True) + temp_file.close() # deletes the file + + def named_tmp_file_mock(**kwargs): + return temp_file + + monkeypatch.setattr( + 'pre_commit.languages.conda.NamedTemporaryFile', + named_tmp_file_mock, + ) + monkeypatch.delattr('pre_commit.languages.conda.os.remove') + with pytest.raises(ValueError) as closed_file_error: + _test_hook_repo( + tempdir_factory, store, 'conda_hooks_repo', + 'additional-deps', [os.devnull], + b'OK\n', + config_kwargs={ + 'hooks': [{ + 'id': 'additional-deps', + 'args': ['-c', 'import tzdata; print("OK")'], + 'additional_dependencies': ['python-tzdata'], + }], + }, + ) + # check raises only one error, the 'closed file' one + assert 'closed file' in str(closed_file_error) + def test_local_conda_additional_dependencies(store): config = {