diff --git a/arc/checks/nmd_test.py b/arc/checks/nmd_test.py index 5fcd89bcfc..07f5b3ee14 100644 --- a/arc/checks/nmd_test.py +++ b/arc/checks/nmd_test.py @@ -8,6 +8,7 @@ import unittest import os import shutil +import tempfile import numpy as np @@ -32,12 +33,14 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_nmd_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.generic_job = job_factory(job_adapter='gaussian', species=[ARCSpecies(label='SPC', smiles='C')], job_type='composite', level=Level(method='CBS-QB3'), project='test_project', - project_directory=os.path.join(ARC_PATH, 'Projects', 'tmp_nmd_project'), + project_directory=os.path.join(cls.scratch_dir, 'tmp_nmd_project'), ) cls.xyz_1 = {'symbols': ('C', 'N', 'H', 'H', 'H', 'H'), 'isotopes': (13, 14, 1, 1, 1, 1), @@ -939,12 +942,8 @@ def test_analyze_ts_normal_mode_displacement_unmapped_reaction(self): def tearDownClass(cls): """ A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests + Delete files created during these unit tests """ - projects = ['tmp_nmd_project'] - for project in projects: - project_directory = os.path.join(ARC_PATH, 'Projects', project) - shutil.rmtree(project_directory, ignore_errors=True) file_paths = [os.path.join(ARC_PATH, 'arc', 'checks', 'nul'), os.path.join(ARC_PATH, 'arc', 'checks', 'run.out')] for file_path in file_paths: if os.path.isfile(file_path): diff --git a/arc/checks/ts_test.py b/arc/checks/ts_test.py index d3ee018c30..f97f15b2c7 100644 --- a/arc/checks/ts_test.py +++ b/arc/checks/ts_test.py @@ -8,6 +8,7 @@ import unittest import os import shutil +import tempfile from unittest.mock import patch import numpy as np @@ -33,6 +34,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_ts_checks_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.rms_list_1 = [0.01414213562373095, 0.05, 0.04, 0.5632938842203065, 0.7993122043357026, 0.08944271909999159, 0.10677078252031312, 0.09000000000000001, 0.05, 0.09433981132056604] @@ -105,9 +108,7 @@ def setUpClass(cls): job_type='composite', level=Level(method='CBS-QB3'), project='test_project', - project_directory=os.path.join(ARC_PATH, - 'Projects', - 'arc_project_for_testing_delete_after_usage4'), + project_directory=os.path.join(cls.scratch_dir, 'job1_project'), ) cls.rxn_3 = ARCReaction(r_species=[ARCSpecies(label='NH3', smiles='N'), ARCSpecies(label='H', smiles='[H]')], @@ -215,7 +216,7 @@ def setUpClass(cls): (-1.1265684046717404, -0.2344009055503307, -1.0127644068816903))} cls.species_dict_8 = {spc.label: spc for spc in cls.rxn_8.r_species + cls.rxn_8.p_species + [cls.rxn_8.ts_species]} - cls.project_directory_8 = os.path.join(ts.ARC_PATH, 'Projects', 'arc_project_for_testing_delete_after_usage5') + cls.project_directory_8 = os.path.join(cls.scratch_dir, 'rxn_8_project') cls.output_dict_8 = {'iC3H7': {'paths': {'freq': os.path.join(ARC_TESTING_PATH, 'freq', 'iC3H7.out'), 'sp': os.path.join(ARC_TESTING_PATH, 'opt', 'iC3H7.out'), 'opt': os.path.join(ARC_TESTING_PATH, 'opt', 'iC3H7.out'), @@ -950,12 +951,8 @@ def test_check_irc_isomorphism_mismatch_alone_is_not_a_failure(self): def tearDownClass(cls): """ A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests + Delete files created during these unit tests """ - projects = ['arc_project_for_testing_delete_after_usage4', 'arc_project_for_testing_delete_after_usage5'] - for project in projects: - project_directory = os.path.join(ARC_PATH, 'Projects', project) - shutil.rmtree(project_directory, ignore_errors=True) file_paths = [os.path.join(ARC_PATH, 'arc', 'checks', 'nul'), os.path.join(ARC_PATH, 'arc', 'checks', 'run.out')] for file_path in file_paths: if os.path.isfile(file_path): diff --git a/arc/common_test.py b/arc/common_test.py index b4b6832faa..d3c9528512 100644 --- a/arc/common_test.py +++ b/arc/common_test.py @@ -8,6 +8,7 @@ import copy import datetime import os +import shutil import tempfile import time import unittest @@ -32,33 +33,11 @@ class TestCommon(unittest.TestCase): """ Contains unit tests for ARC's common module """ - @classmethod - def _clean_globalized_restart_artifact(cls): - """Remove the globalized restart-paths artifact written by - :meth:`test_globalize_paths`. - - Called from BOTH ``setUpClass`` (defensive: wipes a stale - artifact left behind by a previously interrupted run) and - ``tearDownClass`` (the normal cleanup path). This makes the - cleanup self-healing: a Ctrl+C, ``kill``, or hard error during - a previous run cannot leave the next run inheriting the prior - ``restart_paths_globalized.yml``. - """ - globalized_restart_path = os.path.join( - common.ARC_TESTING_PATH, 'restart', '4_globalized_paths', - 'restart_paths_globalized.yml') - if os.path.isfile(globalized_restart_path): - try: - os.remove(path=globalized_restart_path) - except OSError as e: - print(f'Could not remove stale globalized restart artifact {globalized_restart_path}: {e}') - @classmethod def setUpClass(cls): """ A method that is run before all unit tests in this class. """ - cls._clean_globalized_restart_artifact() cls.maxDiff = None cls.default_job_types = {'conf_opt': True, 'opt': True, @@ -991,19 +970,21 @@ def test_get_bonds_from_dmat(self): def test_globalize_paths(self): """Test modifying a file's contents to correct absolute file paths""" - project_directory = os.path.join(common.ARC_TESTING_PATH, 'restart', '4_globalized_paths') + project_directory = os.path.join(tempfile.mkdtemp(prefix='arc_test_globalize_'), '4_globalized_paths') + self.addCleanup(shutil.rmtree, os.path.dirname(project_directory), ignore_errors=True) + shutil.copytree(os.path.join(common.ARC_TESTING_PATH, 'restart', '4_globalized_paths'), project_directory) restart_path = os.path.join(project_directory, 'restart_paths.yml') common.globalize_paths(file_path=restart_path, project_directory=project_directory) globalized_restart_path = os.path.join(project_directory, 'restart_paths_globalized.yml') content = common.read_yaml_file(globalized_restart_path) self.assertEqual(content['output']['restart'], 'Restarted ARC at 2020-02-28 12:51:14.446086; ') - self.assertIn('arc/testing/restart/4_globalized_paths/calcs/Species/HCN/freq_a38229/output.out', + self.assertIn(os.path.join(project_directory, 'calcs', 'Species', 'HCN', 'freq_a38229', 'output.out'), content['output']['spc']['paths']['freq']) self.assertNotIn('gpfs/workspace/users/user', content['output']['spc']['paths']['freq']) path = '/home/user/runs/ARC/ARC_Project/calcs/Species/H/sp_a4339/output.out' new_path = common.globalize_path(path, project_directory) - self.assertIn('arc/testing/restart/4_globalized_paths/calcs/Species/H/sp_a4339/output.out', new_path) + self.assertIn(os.path.join(project_directory, 'calcs', 'Species', 'H', 'sp_a4339', 'output.out'), new_path) def test_globalize_path(self): """Test rebasing a single path to the current ARC project""" @@ -1346,13 +1327,14 @@ def test_calc_rmsd(self): def test_safe_copy_file(self): """tests the safe_copy_file() function.""" + scratch_dir = tempfile.mkdtemp(prefix='arc_test_safe_copy_') + self.addCleanup(shutil.rmtree, scratch_dir, ignore_errors=True) source_path = os.path.join(common.ARC_TESTING_PATH, 'freq', 'CO2_xtb.out') - destination_path = os.path.join(common.ARC_TESTING_PATH, 'freq', 'CO2_xtb_copy.out') + destination_path = os.path.join(scratch_dir, 'CO2_xtb_copy.out') common.safe_copy_file(source=source_path, destination=destination_path) self.assertTrue(os.path.isfile(destination_path)) # Check that no error is being raised if we attempt to copy to the same destination. common.safe_copy_file(source=source_path, destination=destination_path) - os.remove(destination_path) def test_sort_atoms_in_descending_label_order(self): """tests the sort_atoms_in_descending_label_order function""" @@ -1520,13 +1502,6 @@ def test_calculate_arrhenius_rate_coefficient(self): with self.assertRaises(ValueError): common.calculate_arrhenius_rate_coefficient(A=1e12, n=0.5, Ea=10, T=bad_T, Ea_units='kJ/mol') - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - """ - cls._clean_globalized_restart_artifact() - class TestInitializeLogDeferredWarnings(unittest.TestCase): """initialize_log() must flush any deferred import-time warnings diff --git a/arc/job/adapter_test.py b/arc/job/adapter_test.py index 2691aa129a..bdde72263b 100644 --- a/arc/job/adapter_test.py +++ b/arc/job/adapter_test.py @@ -89,13 +89,13 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None - for dir_name in ('test_JobAdapter', 'test_JobAdapter_scan', 'test_JobAdapter_ServerTimeLimit'): - cls.addClassCleanup(shutil.rmtree, os.path.join(ARC_TESTING_PATH, dir_name), ignore_errors=True) + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_job_adapter_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = GaussianAdapter(execution_type='queue', job_type='conf_opt', level=Level(method='cbs-qb3'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_JobAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_JobAdapter'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1', 'O 0 0 2', @@ -124,7 +124,7 @@ def setUpClass(cls): job_type='opt', level=Level(method='cbs-qb3'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_JobAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_JobAdapter'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'])], testing=True, ) @@ -151,7 +151,7 @@ def setUpClass(cls): torsions=[[1, 2, 3, 4]], level=Level(method='wb97xd', basis='def2-tzvp'), project='test_scans', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_JobAdapter_scan'), + project_directory=os.path.join(cls.scratch_dir, 'test_JobAdapter_scan'), species=[cls.spc_3a, cls.spc_3b, cls.spc_3c, cls.spc_3d, cls.spc_3e, cls.spc_3f], testing=True, ) @@ -159,12 +159,12 @@ def setUpClass(cls): job_type='opt', level=Level(method='cbs-qb3'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_JobAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_JobAdapter'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'])], testing=True, ) # Copy the PBS time limit fixture into the directory structure the adapter expects. - stl_dir = os.path.join(ARC_TESTING_PATH, 'test_JobAdapter_ServerTimeLimit') + stl_dir = os.path.join(cls.scratch_dir, 'test_JobAdapter_ServerTimeLimit') err_dest = os.path.join(stl_dir, 'calcs', 'Species', 'spc1', 'opt_101') os.makedirs(err_dest, exist_ok=True) shutil.copy(os.path.join(ARC_TESTING_PATH, 'server', 'pbs', 'timelimit', 'err.txt'), @@ -288,7 +288,7 @@ def test_add_to_args(self): job_type='opt', level=Level(method='cbs-qb3'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_JobAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_JobAdapter'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'])], testing=True, args={'keyword': {'general': 'val_tst_1 val_tst_2 val_tst_3'}, diff --git a/arc/job/adapters/ase_test.py b/arc/job/adapters/ase_test.py index d0e6a542fc..aba745e373 100644 --- a/arc/job/adapters/ase_test.py +++ b/arc/job/adapters/ase_test.py @@ -8,11 +8,12 @@ import os import shutil +import tempfile import unittest from unittest.mock import patch import numpy as np -from arc.common import ARC_TESTING_PATH, read_yaml_file, save_yaml_file +from arc.common import read_yaml_file, save_yaml_file from arc.job.adapters.ase_adapter import ASEAdapter from arc.species.species import ARCSpecies from arc.job.adapters.scripts.ase_script import to_kJmol, numpy_vibrational_analysis, is_linear @@ -29,9 +30,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None - cls.project_directory = os.path.join(ARC_TESTING_PATH, 'test_ASEAdapter') - if not os.path.exists(cls.project_directory): - os.makedirs(cls.project_directory) + cls.project_directory = tempfile.mkdtemp(prefix='arc_test_ase_') + cls.addClassCleanup(shutil.rmtree, cls.project_directory, ignore_errors=True) xyz = {'symbols': ('O', 'H', 'H'), 'isotopes': (16, 1, 1), @@ -204,14 +204,6 @@ def test_numpy_vibrational_analysis(self): for i, val in enumerate(freqs[5:]): self.assertAlmostEqual(results['freqs'][i], val, delta=1e-3) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - shutil.rmtree(cls.project_directory, ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/cfour_test.py b/arc/job/adapters/cfour_test.py index d2bcde5b0a..70a0b7eaf6 100644 --- a/arc/job/adapters/cfour_test.py +++ b/arc/job/adapters/cfour_test.py @@ -8,9 +8,9 @@ import math import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH from arc.job.adapters.cfour import CFourAdapter from arc.level import Level from arc.settings.settings import input_filenames, output_filenames @@ -27,6 +27,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_cfour_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) xyz = {'symbols': ('O', 'C', 'C', 'C', 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'), 'isotopes': (16, 12, 12, 12, 1, 1, 1, 1, 1, 1, 1, 1), 'coords': ((2.094965350070438, -0.6820312883655302, 0.41738812543556636), @@ -45,7 +47,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='CCSD(T)', basis='cc-pVTZ'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_CFourAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_CFourAdapter'), species=[ARCSpecies(label='spc1', xyz=xyz)], testing=True, ) @@ -138,14 +140,6 @@ def test_set_files(self): self.assertEqual(self.job_1.files_to_upload, job_1_files_to_upload) self.assertEqual(self.job_1.files_to_download, job_1_files_to_download) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - shutil.rmtree(os.path.join(ARC_TESTING_PATH, 'test_CFourAdapter'), ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/mockter_test.py b/arc/job/adapters/mockter_test.py index 3dd796091f..39abbe75b6 100644 --- a/arc/job/adapters/mockter_test.py +++ b/arc/job/adapters/mockter_test.py @@ -7,9 +7,10 @@ import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH, read_yaml_file +from arc.common import read_yaml_file from arc.job.adapters.mockter import MockAdapter from arc.level import Level from arc.reaction.reaction import ARCReaction @@ -26,32 +27,34 @@ def setUpClass(cls): """ A method that is run before all unit tests in this class. """ + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_mockter_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = MockAdapter(execution_type='incore', job_type='sp', level=Level(method='CCMockSD(T)', basis='cc-pVmockZ'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MockAdapter_1'), + project_directory=os.path.join(cls.scratch_dir, 'test_MockAdapter_1'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'], multiplicity=3)], testing=True, ) cls.job_2 = MockAdapter(job_type='opt', level=Level(method='CCMockSD(T)', basis='cc-pVmockZ'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MockAdapter_2'), + project_directory=os.path.join(cls.scratch_dir, 'test_MockAdapter_2'), species=[ARCSpecies(label='spc2', xyz=['O 0 0 1'], multiplicity=3)], testing=True, ) cls.job_3 = MockAdapter(job_type='freq', level=Level(method='CCMockSD(T)', basis='cc-pVmockZ'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MockAdapter_3'), + project_directory=os.path.join(cls.scratch_dir, 'test_MockAdapter_3'), species=[ARCSpecies(label='spc3', xyz=['O 0 0 1\nH 0 0 0\nH 1 0 0'], is_ts=True)], testing=True, ) cls.job_4 = MockAdapter(job_type='tsg', level=Level(method='mock)', basis='cc-pVmockZ'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MockAdapter_4'), + project_directory=os.path.join(cls.scratch_dir, 'test_MockAdapter_4'), reactions=[ARCReaction(r_species=[ARCSpecies(label='O', smiles='[O]'), ARCSpecies(label='CCC', smiles='CCC')], p_species=[ARCSpecies(label='OH', smiles='[OH]'), @@ -180,7 +183,7 @@ def test_mockter_freq_count_matches_geometry(self): job = MockAdapter(job_type='freq', level=Level(method='mock', basis='cc-pVmockZ'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, f'test_MockAdapter_freq_{name}'), + project_directory=os.path.join(self.scratch_dir, f'test_MockAdapter_freq_{name}'), species=[ARCSpecies(label=name, xyz=[xyz], multiplicity=multiplicity)], testing=True, ) @@ -190,17 +193,6 @@ def test_mockter_freq_count_matches_geometry(self): msg=f'Expected {expected_num_freqs} freqs for the {name} case, ' f'got {output["freqs"]}.') - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - for folder in ['test_MockAdapter_1', 'test_MockAdapter_2', 'test_MockAdapter_3', 'test_MockAdapter_4', - 'test_MockAdapter_freq_mono', 'test_MockAdapter_freq_diatomic', - 'test_MockAdapter_freq_nonlinear', 'test_MockAdapter_freq_linear']: - shutil.rmtree(os.path.join(ARC_TESTING_PATH, folder), ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/molpro_test.py b/arc/job/adapters/molpro_test.py index 9649875558..80b27592c8 100644 --- a/arc/job/adapters/molpro_test.py +++ b/arc/job/adapters/molpro_test.py @@ -7,9 +7,9 @@ import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH from arc.job.adapters.molpro import MolproAdapter from arc.level import Level from arc.settings.settings import input_filenames, output_filenames @@ -26,11 +26,13 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_molpro_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = MolproAdapter(execution_type='queue', job_type='sp', level=Level(method='CCSD(T)-F12', basis='cc-pVTZ-f12'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MolproAdapter_1'), + project_directory=os.path.join(cls.scratch_dir, 'test_MolproAdapter_1'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'], multiplicity=3)], testing=True, ) @@ -38,7 +40,7 @@ def setUpClass(cls): job_type='opt', level=Level(method='CCSD(T)', basis='cc-pVQZ'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MolproAdapter_2'), + project_directory=os.path.join(cls.scratch_dir, 'test_MolproAdapter_2'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'], multiplicity=3)], testing=True, ) @@ -46,7 +48,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='MRCI', basis='aug-cc-pvtz-f12'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MolproAdapter_3'), + project_directory=os.path.join(cls.scratch_dir, 'test_MolproAdapter_3'), species=[ARCSpecies(label='HNO_t', xyz=["""N -0.08142 0.37454 0.00000 O 1.01258 -0.17285 0.00000 H -0.93116 -0.20169 0.00000"""], @@ -57,7 +59,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='MRCI-F12', basis='aug-cc-pvtz-f12'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MolproAdapter_4'), + project_directory=os.path.join(cls.scratch_dir, 'test_MolproAdapter_4'), species=[ARCSpecies(label='HNO_t', xyz=["""N -0.08142 0.37454 0.00000 O 1.01258 -0.17285 0.00000 H -0.93116 -0.20169 0.00000"""], @@ -68,7 +70,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='MP2_CASSCF_MRCI-F12', basis='aug-cc-pVTZ-F12'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MolproAdapter_5'), + project_directory=os.path.join(cls.scratch_dir, 'test_MolproAdapter_5'), species=[ARCSpecies(label='HNO_t', xyz=["""N -0.08142 0.37454 0.00000 O 1.01258 -0.17285 0.00000 H -0.93116 -0.20169 0.00000"""], @@ -79,7 +81,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='MP2_CASSCF_RS2C', basis='aug-cc-pVTZ'), # CASPT2 project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MolproAdapter_6'), + project_directory=os.path.join(cls.scratch_dir, 'test_MolproAdapter_6'), species=[ARCSpecies(label='HNO_t', xyz=["""N -0.08142 0.37454 0.00000 O 1.01258 -0.17285 0.00000 H -0.93116 -0.20169 0.00000"""], @@ -90,7 +92,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='MP2_CASSCF_RS2C', basis='aug-cc-pVTZ'), # CASPT2 project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_MolproAdapter_7'), + project_directory=os.path.join(cls.scratch_dir, 'test_MolproAdapter_7'), species=[ARCSpecies(label='N', xyz=["""N 0.0 0.0 0.0"""], multiplicity=4, active={'occ': [3, 1, 1, 0, 1, 0, 0, 0], @@ -462,16 +464,6 @@ def test_set_files(self): self.assertEqual(self.job_1.files_to_upload, job_1_files_to_upload) self.assertEqual(self.job_1.files_to_download, job_1_files_to_download) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - for attr in vars(cls).values(): - if isinstance(attr, MolproAdapter): - shutil.rmtree(attr.project_directory, ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/obabel_test.py b/arc/job/adapters/obabel_test.py index 71be5de02c..cf4a09b4bd 100644 --- a/arc/job/adapters/obabel_test.py +++ b/arc/job/adapters/obabel_test.py @@ -7,9 +7,10 @@ import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH, read_yaml_file +from arc.common import read_yaml_file from arc.job.adapters.obabel import OpenbabelAdapter from arc.level import Level from arc.settings.settings import ob_default_settings @@ -27,17 +28,19 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_obabel_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = OpenbabelAdapter(execution_type='incore', job_type='sp', project='test_1', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OpenbabelAdapter_1'), + project_directory=os.path.join(cls.scratch_dir, 'test_OpenbabelAdapter_1'), species=[ARCSpecies(label='EtOH', smiles='CCO')], level=Level(method="MMFF94") ) cls.job_2 = OpenbabelAdapter(execution_type='incore', job_type='opt', project='test_2', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OpenbabelAdapter_2'), + project_directory=os.path.join(cls.scratch_dir, 'test_OpenbabelAdapter_2'), species=[ARCSpecies(label='EtOH', smiles='CCO')], level=Level(method="MMFF94s") ) @@ -53,7 +56,7 @@ def setUpClass(cls): cls.job_3 = OpenbabelAdapter(execution_type='incore', job_type='opt', project='test_3', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OpenbabelAdapter_3'), + project_directory=os.path.join(cls.scratch_dir, 'test_OpenbabelAdapter_3'), species=[ARCSpecies(label='EtOH', smiles='CCO', xyz=etoh_xyz)], constraints=[([1, 2, 3], 109), ([2, 3], 1.4), [(3, 2, 1, 5), 179.8]], level=Level(method="ghemical") @@ -61,14 +64,14 @@ def setUpClass(cls): cls.job_4 = OpenbabelAdapter(execution_type='incore', job_type='opt', project='test_4', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OpenbabelAdapter_4'), + project_directory=os.path.join(cls.scratch_dir, 'test_OpenbabelAdapter_4'), species=[ARCSpecies(label='EtOH', smiles='CCO', xyz=etoh_xyz)], level=Level(method="gaff") ) cls.job_5 = OpenbabelAdapter(execution_type='incore', job_type='sp', project='test_9', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OpenbabelAdapter_5'), + project_directory=os.path.join(cls.scratch_dir, 'test_OpenbabelAdapter_5'), species=[ARCSpecies(label='EtOH', smiles='CCO')], level=Level(method="MMFF94s") ) @@ -151,15 +154,6 @@ def test_write_input_file(self): self.assertIn('C', content['xyz']) self.assertTrue(content['xyz'].strip().startswith('9')) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - for i in list(range(1, 6)): - path = os.path.join(ARC_TESTING_PATH, f'test_OpenbabelAdapter_{i}') - shutil.rmtree(path, ignore_errors=True) if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/orca_test.py b/arc/job/adapters/orca_test.py index c0ce422c89..fcf956b364 100644 --- a/arc/job/adapters/orca_test.py +++ b/arc/job/adapters/orca_test.py @@ -9,9 +9,9 @@ import math import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH from arc.job.adapters.orca import (OrcaAdapter, _format_orca_basis, _format_orca_basis_token, @@ -32,11 +32,13 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_orca_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = OrcaAdapter(execution_type='queue', job_type='sp', level=Level(method='DLPNO-CCSD(T)', basis='def2-tzvp', auxiliary_basis='def2-tzvp/c'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -50,7 +52,7 @@ def setUpClass(cls): level=Level(method='DLPNO-CCSD(T)', basis='def2-tzvp', auxiliary_basis='def2-tzvp/c', solvation_method='SMD', solvent='DMSO'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -64,7 +66,7 @@ def setUpClass(cls): level=Level(method='DLPNO-CCSD(T)', basis='def2-tzvp', auxiliary_basis='def2-tzvp/c', solvation_method='cpcm', solvent='water'), project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -77,7 +79,7 @@ def setUpClass(cls): job_type='sp', level=Level(method='MP2_CASSCF_MRCI', basis='aug-cc-pVTZ'), project='test4', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(cls.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', active=(14, 7), xyz="""C 0.03807240 0.00035621 -0.00484242 @@ -197,7 +199,7 @@ def test_write_input_file_f12_with_cabs(self): auxiliary_basis='aug-cc-pVTZ/C', cabs='cc-pVTZ-F12-CABS'), project='test_f12', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='O_atom', smiles='[O]', xyz='O 0.0 0.0 0.0')], testing=True, @@ -223,7 +225,7 @@ def test_write_input_file_f12_without_cabs_raises(self): basis='cc-pVTZ-F12', auxiliary_basis='aug-cc-pVTZ/C'), project='test_f12_bad', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='O_atom', smiles='[O]', xyz='O 0.0 0.0 0.0')], testing=True, @@ -321,7 +323,7 @@ def test_dft_grid_regular_opt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -343,7 +345,7 @@ def test_dft_grid_fine_opt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid_fine', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -364,7 +366,7 @@ def test_dft_grid_freq(self): job_type='freq', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid_freq', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -385,7 +387,7 @@ def test_dft_grid_optfreq(self): job_type='optfreq', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_dft_grid_optfreq', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -406,7 +408,7 @@ def test_fine_opt_convergence_tightopt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_fine_opt_conv', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -428,7 +430,7 @@ def test_recalc_hess_in_optts(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_optts_hess', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='TS_example', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -454,7 +456,7 @@ def test_recalc_hess_not_in_regular_opt(self): job_type='opt', level=Level(method='wb97x-d3', basis='def2-tzvp'), project='test_opt_no_hess', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -483,7 +485,7 @@ def test_writing_input_does_not_pollute_level_args(self): job_type='opt', level=level, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), + project_directory=os.path.join(self.scratch_dir, 'test_OrcaAdapter'), species=[ARCSpecies(label='CH3O', xyz="""C 0.03807240 0.00035621 -0.00484242 O 1.35198769 0.01264937 -0.17195885 @@ -497,14 +499,6 @@ def test_writing_input_does_not_pollute_level_args(self): self.assertEqual(level.args, {'keyword': dict(), 'block': dict()}) self.assertNotIn('args', level.as_dict()) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - shutil.rmtree(os.path.join(ARC_TESTING_PATH, 'test_OrcaAdapter'), ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/pyscf_test.py b/arc/job/adapters/pyscf_test.py index 42253850ca..fca1b242b7 100644 --- a/arc/job/adapters/pyscf_test.py +++ b/arc/job/adapters/pyscf_test.py @@ -12,10 +12,11 @@ import importlib.util import os import shutil +import tempfile import unittest from unittest.mock import patch -from arc.common import ARC_TESTING_PATH, read_yaml_file, save_yaml_file +from arc.common import read_yaml_file, save_yaml_file from arc.job.adapters.pyscf_adapter import PySCFAdapter from arc.level import Level from arc.parser.adapters.yaml import YAMLParser @@ -35,9 +36,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None - cls.project_directory = os.path.join(ARC_TESTING_PATH, 'test_PySCFAdapter') - if not os.path.exists(cls.project_directory): - os.makedirs(cls.project_directory) + cls.project_directory = tempfile.mkdtemp(prefix='arc_test_pyscf_') + cls.addClassCleanup(shutil.rmtree, cls.project_directory, ignore_errors=True) water_xyz = {'symbols': ('O', 'H', 'H'), 'isotopes': (16, 1, 1), @@ -242,14 +242,6 @@ def test_normalize_basis(self): self.assertEqual(normalize_basis('def2SVP'), 'def2-svp') self.assertEqual(normalize_basis('cc-pvtz'), 'cc-pvtz') - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests. - """ - shutil.rmtree(cls.project_directory, ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/ts/gcn_test.py b/arc/job/adapters/ts/gcn_test.py index 27498871fd..ff8255182d 100644 --- a/arc/job/adapters/ts/gcn_test.py +++ b/arc/job/adapters/ts/gcn_test.py @@ -9,12 +9,12 @@ import os import shutil import subprocess +import tempfile import unittest from unittest.mock import patch from arc.common import ARC_PATH, ARC_TESTING_PATH, read_yaml_file import arc.job.adapters.ts.gcn_ts as ts_gcn -from arc.job.adapters.ts.gcn_ts import GCNAdapter from arc.reaction import ARCReaction from arc.species.converter import str_to_xyz from arc.species.species import ARCSpecies, TSGuess @@ -72,8 +72,7 @@ def setUp(self): Tests run in parallel (pytest-xdist), so each test gets its own directory. """ self.maxDiff = None - self.output_dir = os.path.join(ARC_TESTING_PATH, f'GCN_{self._testMethodName}') - os.makedirs(self.output_dir, exist_ok=True) + self.output_dir = tempfile.mkdtemp(prefix='arc_test_gcn_') self.addCleanup(shutil.rmtree, self.output_dir, ignore_errors=True) self.reactant_path = os.path.join(self.output_dir, 'react.sdf') self.product_path = os.path.join(self.output_dir, 'prod.sdf') @@ -85,16 +84,16 @@ def get_reaction() -> ARCReaction: return ARCReaction(r_species=[ARCSpecies(label='nC3H7', smiles='[CH2]CC')], p_species=[ARCSpecies(label='iC3H7', smiles='C[CH]C')]) - def get_adapter(self, rxn: ARCReaction) -> GCNAdapter: + def get_adapter(self, rxn: ARCReaction) -> ts_gcn.GCNAdapter: """Get a GCNAdapter instance for testing.""" project_dir = os.path.join(self.output_dir, 'project') - return GCNAdapter(job_type='tsg', - reactions=[rxn], - testing=True, - project='test_GCNAdapter', - project_directory=project_dir, - dihedral_increment=1, - ) + return ts_gcn.GCNAdapter(job_type='tsg', + reactions=[rxn], + testing=True, + project='test_GCNAdapter', + project_directory=project_dir, + dihedral_increment=1, + ) def test_gcn_available(self): """Test the gcn_available() function.""" @@ -238,8 +237,7 @@ def setUp(self): A method that is run before each unit test in this class. """ self.maxDiff = None - self.output_dir = os.path.join(ARC_TESTING_PATH, f'GCN_script_{self._testMethodName}') - os.makedirs(self.output_dir, exist_ok=True) + self.output_dir = tempfile.mkdtemp(prefix='arc_test_gcn_script_') self.addCleanup(shutil.rmtree, self.output_dir, ignore_errors=True) self.gcn_script = load_gcn_script() diff --git a/arc/job/adapters/ts/heuristics_test.py b/arc/job/adapters/ts/heuristics_test.py index ea7de2d8b5..8369ee95c2 100644 --- a/arc/job/adapters/ts/heuristics_test.py +++ b/arc/job/adapters/ts/heuristics_test.py @@ -9,9 +9,10 @@ import itertools import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH, almost_equal_coords +from arc.common import almost_equal_coords from arc.family import get_reaction_family_products from arc.job.adapters.ts.heuristics import (HeuristicsAdapter, are_h_abs_wells_reversed, @@ -53,6 +54,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_heuristics_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.oh_xyz = """O 0.0000000 0.0000000 0.1078170 H 0.0000000 0.0000000 -0.8625320""" cls.h2o_xyz = """O -0.00032832 0.39781490 0.00000000 @@ -468,7 +471,7 @@ def test_heuristics_for_h_abstraction_1(self): reactions=[rxn1], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=10, ) heuristics_1.execute_incore() @@ -487,7 +490,7 @@ def test_heuristics_for_h_abstraction_1(self): reactions=[rxn2], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=10, ) heuristics_2.execute_incore() @@ -505,7 +508,7 @@ def test_heuristics_for_h_abstraction_1(self): reactions=[rxn3], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=10, ) heuristics_3.execute_incore() @@ -531,7 +534,7 @@ def test_heuristics_for_h_abstraction_1(self): reactions=[rxn4], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=120, ) heuristics_4.execute_incore() @@ -601,7 +604,7 @@ def test_heuristics_for_h_abstraction_2(self): reactions=[rxn5], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=120, ) heuristics_5.execute_incore() @@ -653,7 +656,7 @@ def test_heuristics_for_h_abstraction_3(self): reactions=[rxn6], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=20, ) heuristics_6.execute_incore() @@ -688,7 +691,7 @@ def test_heuristics_for_h_abstraction_4(self): reactions=[rxn7], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=120, ) heuristics_7.execute_incore() @@ -722,7 +725,7 @@ def test_heuristics_for_h_abstraction_5(self): reactions=[rxn8], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=120, ) heuristics_8.execute_incore() @@ -861,7 +864,7 @@ def test_heuristics_for_h_abstraction_6(self): reactions=[rxn9], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=120, ) heuristics_9.execute_incore() @@ -877,7 +880,7 @@ def test_heuristics_for_h_abstraction_6(self): reactions=[rxn10], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=120, ) heuristics_10.execute_incore() @@ -930,7 +933,7 @@ def test_heuristics_for_h_abstraction_7(self): reactions=[rxn11], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=30, ) heuristics_11.execute_incore() @@ -953,7 +956,7 @@ def test_heuristics_for_h_abstraction_8(self): reactions=[rxn12], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=60, ) heuristics_12.execute_incore() @@ -973,7 +976,7 @@ def test_heuristics_for_h_abstraction_8(self): reactions=[rxn13], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=180, ) heuristics_13.execute_incore() @@ -991,7 +994,7 @@ def test_heuristics_for_h_abstraction_8(self): reactions=[rxn14], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=180, ) heuristics_14.execute_incore() @@ -1009,7 +1012,7 @@ def test_heuristics_for_h_abstraction_8(self): reactions=[rxn15], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=180, ) heuristics_15.execute_incore() @@ -1034,7 +1037,7 @@ def test_heuristics_for_h_abstraction_9(self): reactions=[rxn16], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=360, ) heuristics_16.execute_incore() @@ -1061,7 +1064,7 @@ def test_heuristics_for_h_abstraction_10(self): reactions=[rxn17], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=60, ) heuristics_16.execute_incore() @@ -1081,7 +1084,7 @@ def test_heuristics_for_h_abstraction_11(self): reactions=[rxn1], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=60, ) heuristics_1.execute_incore() @@ -1100,7 +1103,7 @@ def test_heuristics_for_h_abstraction_12(self): reactions=[rxn1], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=60, ) heuristics_1.execute_incore() @@ -1119,7 +1122,7 @@ def test_heuristics_for_h_abstraction_13(self): reactions=[rxn1], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=60, ) heuristics_1.execute_incore() @@ -1135,7 +1138,7 @@ def test_heuristics_for_h_abstraction_13(self): reactions=[rxn1], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics'), + project_directory=os.path.join(self.scratch_dir, 'heuristics'), dihedral_increment=120, ) heuristics_1.execute_incore() @@ -1152,7 +1155,7 @@ def test_heuristics_for_carbonyl_based_hydrolysis(self): reactions=[rxn], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics_carbonyl')) + project_directory=os.path.join(self.scratch_dir, 'heuristics_carbonyl')) adapter.execute_incore() self.assertEqual(rxn.family, 'carbonyl_based_hydrolysis') self.assertTrue(rxn.ts_species.is_ts) @@ -1170,7 +1173,7 @@ def test_heuristics_for_ether_hydrolysis(self): reactions=[rxn], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics_ether')) + project_directory=os.path.join(self.scratch_dir, 'heuristics_ether')) adapter.execute_incore() self.assertEqual(rxn.family, 'ether_hydrolysis') self.assertTrue(rxn.ts_species.is_ts) @@ -1188,7 +1191,7 @@ def test_heuristics_for_nitrile_hydrolysis(self): reactions=[rxn], testing=True, project='test', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics_nitrile')) + project_directory=os.path.join(self.scratch_dir, 'heuristics_nitrile')) adapter.execute_incore() self.assertEqual(rxn.family, 'nitrile_hydrolysis') self.assertTrue(rxn.ts_species.is_ts) @@ -1213,7 +1216,7 @@ def test_keeping_atom_order_in_ts(self): reactions=[rxn_1], testing=True, project='test_1', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics_1'), + project_directory=os.path.join(self.scratch_dir, 'heuristics_1'), dihedral_increment=120, ) heuristics_1.execute_incore() @@ -1237,7 +1240,7 @@ def test_keeping_atom_order_in_ts(self): reactions=[rxn_2], testing=True, project='test_1', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics_1'), + project_directory=os.path.join(self.scratch_dir, 'heuristics_1'), dihedral_increment=120, ) heuristics_2.execute_incore() @@ -1261,7 +1264,7 @@ def test_keeping_atom_order_in_ts(self): reactions=[rxn_3], testing=True, project='test_1', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics_1'), + project_directory=os.path.join(self.scratch_dir, 'heuristics_1'), dihedral_increment=120, ) heuristics_3.execute_incore() @@ -1284,7 +1287,7 @@ def test_keeping_atom_order_in_ts(self): reactions=[rxn_4], testing=True, project='test_1', - project_directory=os.path.join(ARC_TESTING_PATH, 'heuristics_1'), + project_directory=os.path.join(self.scratch_dir, 'heuristics_1'), dihedral_increment=120, ) heuristics_4.execute_incore() @@ -2255,15 +2258,6 @@ def test_check_ts_bonds(self): result = check_ts_bonds(initial_xyz, [7, 8, 9, 2, 4]) self.assertTrue(result) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests. - """ - for sub in ('heuristics', 'heuristics_1', 'heuristics_carbonyl', 'heuristics_ether', 'heuristics_nitrile'): - shutil.rmtree(os.path.join(ARC_TESTING_PATH, sub), ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/job/adapters/ts/kinbot_test.py b/arc/job/adapters/ts/kinbot_test.py index 5b8ddaded3..d2616097c3 100644 --- a/arc/job/adapters/ts/kinbot_test.py +++ b/arc/job/adapters/ts/kinbot_test.py @@ -9,16 +9,15 @@ import os import shutil import subprocess +import tempfile import unittest -from unittest import mock +import unittest.mock as mock -from arc.common import ARC_TESTING_PATH, get_logger, read_yaml_file, save_yaml_file +from arc.common import read_yaml_file, save_yaml_file import arc.job.adapters.ts.kinbot_ts as kinbot_ts from arc.reaction import ARCReaction from arc.species import ARCSpecies -logger = get_logger() - def kinbot_list_to_coords(structure: list) -> list: """A helper function to convert a flat KinBot structure list into an N x 3 coordinates list.""" @@ -39,7 +38,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None - cls.project_dir = os.path.join(ARC_TESTING_PATH, 'test_KinBot') + cls.project_dir = tempfile.mkdtemp(prefix='arc_test_kinbot_') + cls.addClassCleanup(shutil.rmtree, cls.project_dir, ignore_errors=True) def setUp(self): """ @@ -49,21 +49,9 @@ def setUp(self): r_species=[ARCSpecies(label='CC[O]', smiles='CC[O]')], p_species=[ARCSpecies(label='[CH2]CO', smiles='[CH2]CO')]) - def _remove_test_dir(self, path: str): - """A helper function to remove a single test's project directory (and the shared - parent directory if it is empty). Tests may run in parallel (pytest-xdist), so - each test must only ever remove its own subdirectory.""" - shutil.rmtree(path, ignore_errors=True) - try: - os.rmdir(self.project_dir) - except OSError: - logger.debug(f'Could not remove shared parent dir {self.project_dir} during teardown ' - f'(non-empty or already removed by a parallel worker).') - def get_adapter(self, dir_name: str) -> kinbot_ts.KinBotAdapter: """A helper function to instantiate a KinBotAdapter instance.""" project_directory = os.path.join(self.project_dir, dir_name) - self.addCleanup(self._remove_test_dir, project_directory) return kinbot_ts.KinBotAdapter(job_type='tsg', reactions=[self.rxn_1], testing=True, diff --git a/arc/job/adapters/ts/orca_neb_test.py b/arc/job/adapters/ts/orca_neb_test.py index 1930c58dc6..468344dc4b 100644 --- a/arc/job/adapters/ts/orca_neb_test.py +++ b/arc/job/adapters/ts/orca_neb_test.py @@ -8,11 +8,11 @@ import os import shutil import datetime +import tempfile import unittest import unittest.mock import pytest -from arc.common import ARC_TESTING_PATH from arc.job.adapters.ts.orca_neb import OrcaNEBAdapter from arc.level import Level from arc.reaction import ARCReaction @@ -31,11 +31,8 @@ def setUpClass(cls): """ cls.maxDiff = None - cls.project_directory = os.path.join(ARC_TESTING_PATH, 'test_OrcaNEBAdapter') - if os.path.exists(cls.project_directory): - shutil.rmtree(cls.project_directory) + cls.project_directory = tempfile.mkdtemp(prefix='arc_test_orca_neb_') cls.addClassCleanup(shutil.rmtree, cls.project_directory, ignore_errors=True) - os.makedirs(cls.project_directory) # Mock objects for both orca_neb and orca/adapter modules mock_input_filenames = {'orca_neb': 'input.in', 'orca': 'input.in'} diff --git a/arc/job/adapters/ts/xtbgsm_test.py b/arc/job/adapters/ts/xtbgsm_test.py index 4355fab580..4a06fbdb27 100644 --- a/arc/job/adapters/ts/xtbgsm_test.py +++ b/arc/job/adapters/ts/xtbgsm_test.py @@ -7,9 +7,9 @@ import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH from arc.job.adapters.ts.xtb_gsm import xTBGSMAdapter from arc.level import Level from arc.parser.parser import parse_trajectory @@ -28,12 +28,11 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None - for i in range(10): - cls.addClassCleanup(shutil.rmtree, os.path.join(ARC_TESTING_PATH, f'test_xTBAGSMdapter_{i}'), - ignore_errors=True) + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_xtb_gsm_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = xTBGSMAdapter(project='test_1', job_type='tsg', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAGSMdapter_1'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAGSMdapter_1'), reactions=[ARCReaction(r_species=[ARCSpecies(label='HNO', smiles='N=O')], p_species=[ARCSpecies(label='HON', smiles='[N-]=[OH+]')])], ) @@ -46,7 +45,7 @@ def setUpClass(cls): 'add_node_tol': 0.5, 'final_opt': 10, 'nnodes': 9}}), - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAGSMdapter_2'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAGSMdapter_2'), reactions=[ARCReaction(r_species=[ARCSpecies(label='HNO', smiles='N=O')], p_species=[ARCSpecies(label='HON', smiles='[N-]=[OH+]')])], ) diff --git a/arc/job/adapters/uma_test.py b/arc/job/adapters/uma_test.py index bea1775271..7e937a5c01 100644 --- a/arc/job/adapters/uma_test.py +++ b/arc/job/adapters/uma_test.py @@ -12,10 +12,11 @@ import os import shutil import sys +import tempfile import unittest import unittest.mock -from arc.common import ARC_TESTING_PATH, almost_equal_coords, read_yaml_file, save_yaml_file +from arc.common import almost_equal_coords, read_yaml_file, save_yaml_file from arc.job.adapters.ase_adapter import ASEAdapter from arc.level import Level from arc.parser.parser import (parse_1d_scan_coords, parse_e_elect, parse_frequencies, @@ -51,8 +52,8 @@ class TestUMAViaASEAdapter(unittest.TestCase): def setUpClass(cls): """A method that is run before all unit tests in this class.""" cls.maxDiff = None - cls.base = os.path.join(ARC_TESTING_PATH, 'test_UMA_via_ASE') - os.makedirs(cls.base, exist_ok=True) + cls.base = tempfile.mkdtemp(prefix='arc_test_uma_') + cls.addClassCleanup(shutil.rmtree, cls.base, ignore_errors=True) # UMA selected implicitly via the level method. cls.job_method = ASEAdapter(execution_type='incore', job_type='sp', project='p', project_directory=os.path.join(cls.base, 'method'), @@ -66,11 +67,6 @@ def setUpClass(cls): for job in (cls.job_method, cls.job_args): os.makedirs(job.local_path, exist_ok=True) - @classmethod - def tearDownClass(cls): - """A method that is run after all unit tests in this class.""" - shutil.rmtree(cls.base, ignore_errors=True) - def test_determine_calculator_name(self): """Test that the UMA calculator is detected from the level method or from args.""" self.assertEqual(self.job_method.determine_calculator_name(), 'uma') @@ -153,12 +149,8 @@ class TestUMAViaASEWithModel(unittest.TestCase): @classmethod def setUpClass(cls): """A method that is run before all unit tests in this class.""" - cls.base = os.path.join(ARC_TESTING_PATH, 'test_UMA_via_ASE_model') - - @classmethod - def tearDownClass(cls): - """A method that is run after all unit tests in this class.""" - shutil.rmtree(cls.base, ignore_errors=True) + cls.base = tempfile.mkdtemp(prefix='arc_test_uma_model_') + cls.addClassCleanup(shutil.rmtree, cls.base, ignore_errors=True) def _job(self, label, job_type, species, **kwargs): """Build an incore UMA-via-ASE job.""" diff --git a/arc/job/adapters/xtb_test.py b/arc/job/adapters/xtb_test.py index b4b4937f14..ffc803cb93 100644 --- a/arc/job/adapters/xtb_test.py +++ b/arc/job/adapters/xtb_test.py @@ -7,9 +7,10 @@ import os import shutil +import tempfile import unittest -from arc.common import ARC_TESTING_PATH, almost_equal_coords +from arc.common import almost_equal_coords from arc.job.adapters.xtb_adapter import xTBAdapter from arc.level import Level from arc.parser.parser import parse_e_elect, parse_frequencies, parse_geometry @@ -27,11 +28,13 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_xtb_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.job_1 = xTBAdapter(execution_type='queue', job_type='sp', project='test_1', level=Level(method='gfn1', args={'keyword': {'parallel': 'no'}}), - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_1'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_1'), species=[ARCSpecies(label='spc1', xyz=['O 0 0 1'], multiplicity=3)], testing=True, ) @@ -39,7 +42,7 @@ def setUpClass(cls): job_type='opt', project='test_2', fine=True, - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_2'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_2'), species=[ARCSpecies(label='spc2', smiles='CC[O]')], testing=True, ) @@ -47,7 +50,7 @@ def setUpClass(cls): job_type='scan', project='test_3', torsions=[[0, 1, 2, 3]], - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_3'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_3'), species=[ARCSpecies(label='spc1', xyz="""O 1.09412318 -0.31048292 0.52221323 N -0.00341051 0.01666411 0.06406731 O -0.88296129 -0.72127547 -0.38686359 @@ -60,27 +63,27 @@ def setUpClass(cls): torsions=[[5, 6, 1, 4]], project='test_4', fine=True, - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_4'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_4'), species=[ARCSpecies(label='EtOH', smiles='CCO')], testing=True, ) cls.job_5 = xTBAdapter(execution_type='incore', job_type='sp', project='test_5', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_5'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_5'), species=[ARCSpecies(label='NCC', smiles='NCC')] ) cls.job_6 = xTBAdapter(execution_type='incore', job_type='freq', project='test_6', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_6'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_6'), species=[ARCSpecies(label='HO2', smiles='O[O]')] ) cls.job_7 = xTBAdapter(execution_type='queue', job_type='opt', project='test_7', fine=True, - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_7'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_7'), species=[ARCSpecies(label='spc7', xyz='O 0 0 1', multiplicity=3)], testing=True, ) @@ -89,7 +92,7 @@ def setUpClass(cls): cls.job_8 = xTBAdapter(job_type='scan', level=Level(method='xtb'), project='test_8', - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_8'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_8'), species=[spc_8], rotor_index=0, ) @@ -97,14 +100,14 @@ def setUpClass(cls): job_type='opt', project='test_9', level=Level(method='xtb', solvent='water', solvation_method="alpb"), - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_9'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_9'), species=[ARCSpecies(label='spc2', smiles='CC[O]')], ) cls.job_10 = xTBAdapter(execution_type='incore', job_type='opt', project='test_10', level=Level(method='gfn2'), - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_10'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_10'), species=[ARCSpecies(label='TS', is_ts=True, xyz="""C -1.317288 -0.260819 -0.032638 C -0.041481 0.531329 0.023478 @@ -134,14 +137,14 @@ def setUpClass(cls): job_type='freq', project='test_11', level=Level(method='gfn2'), - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_11'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_11'), species=[ARCSpecies(label='TS', is_ts=True, xyz=cls.ts_xyz)], ) cls.job_12 = xTBAdapter(execution_type='incore', job_type='freq', project='test_12', level=Level(method='gfn2'), - project_directory=os.path.join(ARC_TESTING_PATH, 'test_xTBAdapter_12'), + project_directory=os.path.join(cls.scratch_dir, 'test_xTBAdapter_12'), species=[ARCSpecies(label='H2', smiles='[H][H]')], ) @@ -287,16 +290,6 @@ def test_scan(self): self.job_8.execute() self.assertTrue(os.path.isfile(os.path.join(self.job_8.local_path, 'xtbscan.log'))) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - for i in range(20): - path = os.path.join(ARC_TESTING_PATH, f'test_xTBAdapter_{i}') - shutil.rmtree(path, ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/main_test.py b/arc/main_test.py index 64282cc7fc..4e23f081ea 100644 --- a/arc/main_test.py +++ b/arc/main_test.py @@ -11,9 +11,9 @@ import subprocess import tempfile import unittest -from unittest import mock +import unittest.mock as mock -from arc.common import ARC_PATH, get_logger +from arc.common import get_logger from arc.exceptions import InputError from arc.imports import settings from arc.job.adapters.gaussian import GaussianAdapter @@ -36,6 +36,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_main_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.servers = servers.keys() cls.job_types1 = {'conf_opt': True, 'opt': True, @@ -48,12 +50,6 @@ def setUpClass(cls): 'lennard_jones': False, 'bde': True, } - projects = ['arc_project_for_testing_delete_after_usage_test_from_dict', - 'arc_model_chemistry_test', 'arc_test', 'test', 'unit_test_specific_job', 'wrong'] - for project in projects: - project_directory = os.path.join(ARC_PATH, 'Projects', project) - if os.path.isdir(project_directory): - shutil.rmtree(project_directory, ignore_errors=True) def test_as_dict(self): """Test the as_dict() method of ARC""" @@ -62,6 +58,7 @@ def test_as_dict(self): compute_thermo=False, ) arc0 = ARC(project='arc_test', + project_directory=os.path.join(self.scratch_dir, 'arc_test'), job_types=self.job_types1, species=[spc1], level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)', @@ -178,10 +175,12 @@ def test_from_dict(self): 'optical_isomers': 1, 'rotors_dict': {}, 'xyzs': []}], - 'project_directory': os.path.join(ARC_PATH, 'Projects', - 'arc_project_for_testing_delete_after_usage_test_from_dict'), + 'project_directory': os.path.join( + self.scratch_dir, 'arc_project_for_testing_delete_after_usage_test_from_dict'), } - arc1 = ARC(project='wrong', freq_scale_factor=0.95) + arc1 = ARC(project='wrong', + project_directory=os.path.join(self.scratch_dir, 'wrong'), + freq_scale_factor=0.95) self.assertEqual(arc1.freq_scale_factor, 0.95) # user input arc2 = ARC(**restart_dict) self.assertEqual(arc2.freq_scale_factor, 0.96) # loaded from the restart dict @@ -199,7 +198,7 @@ def test_from_dict_specific_job(self): """Test the from_dict() method of ARC""" restart_dict = {'specific_job_type': 'bde', 'project': 'unit_test_specific_job', - 'project_directory': os.path.join(ARC_PATH, 'Projects', 'unit_test_specific_job'), + 'project_directory': os.path.join(self.scratch_dir, 'unit_test_specific_job'), } arc1 = ARC(**restart_dict) job_type_expected = {'conf_opt': False, 'conf_sp': False, 'opt': True, 'freq': True, 'sp': True, 'rotors': False, @@ -219,21 +218,27 @@ def test_check_project_name(self): def test_determine_model_chemistry_and_freq_scale_factor(self): """Test determining the model chemistry and the frequency scaling factor""" - arc0 = ARC(project='arc_model_chemistry_test', level_of_theory='CBS-QB3') + arc0 = ARC(project='arc_model_chemistry_test', + project_directory=os.path.join(self.scratch_dir, 'arc_model_chemistry_test'), + level_of_theory='CBS-QB3') self.assertEqual(str(arc0.arkane_level_of_theory), "cbs-qb3, software: gaussian") self.assertEqual(arc0.freq_scale_factor, 1.004) - arc1 = ARC(project='arc_model_chemistry_test', level_of_theory='cbs-qb3-paraskevas') + arc1 = ARC(project='arc_model_chemistry_test', + project_directory=os.path.join(self.scratch_dir, 'arc_model_chemistry_test'), + level_of_theory='cbs-qb3-paraskevas') self.assertEqual(str(arc1.arkane_level_of_theory), 'cbs-qb3-paraskevas, software: gaussian') self.assertEqual(arc1.freq_scale_factor, 1.004) self.assertEqual(arc1.bac_type, 'p') arc2 = ARC(project='arc_model_chemistry_test', + project_directory=os.path.join(self.scratch_dir, 'arc_model_chemistry_test'), level_of_theory='ccsd(t)-f12/cc-pvtz-f12//m062x/cc-pvtz') self.assertEqual(str(arc2.arkane_level_of_theory), 'ccsd(t)-f12/cc-pvtz-f12, software: molpro') self.assertEqual(arc2.freq_scale_factor, 0.955) arc3 = ARC(project='arc_model_chemistry_test', + project_directory=os.path.join(self.scratch_dir, 'arc_model_chemistry_test'), sp_level='ccsd(t)-f12/cc-pvtz-f12', opt_level='wb97xd/def2tzvp') self.assertEqual(str(arc3.arkane_level_of_theory), 'ccsd(t)-f12/cc-pvtz-f12, software: molpro') self.assertEqual(arc3.freq_scale_factor, 0.988) @@ -242,33 +247,46 @@ def test_determine_model_chemistry_for_job_types(self): """Test determining the model chemistry specification dictionary for job types""" # Test conflicted inputs: specify both level_of_theory and composite_method with self.assertRaises(InputError): - ARC(project='test', level_of_theory='ccsd(t)-f12/cc-pvtz-f12//wb97x-d/aug-cc-pvtz', + ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + level_of_theory='ccsd(t)-f12/cc-pvtz-f12//wb97x-d/aug-cc-pvtz', composite_method='cbs-qb3') # Test illegal level of theory specification (method contains multiple slashes) with self.assertRaises(ValueError): - ARC(project='test', level_of_theory='dlpno-mp2-f12/D/cc-pVDZ(fi/sf/fw)//b3lyp/G/def2svp') + ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + level_of_theory='dlpno-mp2-f12/D/cc-pVDZ(fi/sf/fw)//b3lyp/G/def2svp') # Test illegal job level specification (method contains multiple slashes) with self.assertRaises(ValueError): - ARC(project='test', opt_level='b3lyp/d/def2tzvp/def2tzvp/c') + ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + opt_level='b3lyp/d/def2tzvp/def2tzvp/c') # Test illegal job level specification (method contains empty space) with self.assertRaises(ValueError): - ARC(project='test', opt_level='b3lyp/def2tzvp def2tzvp/c') + ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + opt_level='b3lyp/def2tzvp def2tzvp/c') # Test direct job level specification conflicts with level of theory specification with self.assertRaises(InputError): - ARC(project='test', level_of_theory='b3lyp/sto-3g', opt_level='wb97xd/def2tzvp') + ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + level_of_theory='b3lyp/sto-3g', opt_level='wb97xd/def2tzvp') # Test deduce levels from default method from settings.py - arc1 = ARC(project='test') + arc1 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test')) self.assertEqual(arc1.opt_level.simple(), 'wb97xd/def2tzvp') self.assertEqual(arc1.freq_level.simple(), 'wb97xd/def2tzvp') self.assertEqual(arc1.sp_level.simple(), 'ccsd(t)-f12/cc-pvtz-f12') # Test deduce levels from composite method specification - arc2 = ARC(project='test', composite_method='cbs-qb3') + arc2 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + composite_method='cbs-qb3') self.assertIsNotNone(arc2.opt_level) self.assertIsNone(arc2.sp_level) self.assertIsNone(arc2.orbitals_level) @@ -277,35 +295,47 @@ def test_determine_model_chemistry_for_job_types(self): self.assertEqual(arc2.composite_method.simple(), 'cbs-qb3') # Test deduce levels from level of theory specification - arc3 = ARC(project='test', level_of_theory='ccsd(t)-f12/cc-pvtz-f12//wb97m-v/def2tzvpd', freq_scale_factor=1) + arc3 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + level_of_theory='ccsd(t)-f12/cc-pvtz-f12//wb97m-v/def2tzvpd', freq_scale_factor=1) self.assertEqual(arc3.opt_level.simple(), 'wb97m-v/def2tzvpd') self.assertEqual(arc3.freq_level.simple(), 'wb97m-v/def2tzvpd') self.assertEqual(arc3.sp_level.simple(), 'ccsd(t)-f12/cc-pvtz-f12') self.assertEqual(arc3.scan_level.simple(), 'wb97m-v/def2tzvpd') self.assertIsNone(arc3.orbitals_level) - arc4 = ARC(project='test', opt_level='wb97x-d3/6-311++G(3df,3pd)', freq_level='m062x/def2-tzvpp', + arc4 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + opt_level='wb97x-d3/6-311++G(3df,3pd)', freq_level='m062x/def2-tzvpp', sp_level='ccsd(t)f12/aug-cc-pvqz', calc_freq_factor=False, compute_thermo=False) self.assertEqual(arc4.opt_level.simple(), 'wb97x-d3/6-311++g(3df,3pd)') self.assertEqual(arc4.freq_level.simple(), 'm062x/def2-tzvpp') self.assertEqual(arc4.sp_level.simple(), 'ccsd(t)f12/aug-cc-pvqz') # Test deduce freq level from opt level - arc7 = ARC(project='test', opt_level='wb97xd/aug-cc-pvtz', calc_freq_factor=False) + arc7 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + opt_level='wb97xd/aug-cc-pvtz', calc_freq_factor=False) self.assertEqual(arc7.opt_level.simple(), 'wb97xd/aug-cc-pvtz') self.assertEqual(arc7.freq_level.simple(), 'wb97xd/aug-cc-pvtz') # Test a level not supported by Arkane does not raise error if compute_thermo is False - arc8 = ARC(project='test', sp_level='method/unsupported', calc_freq_factor=False, compute_thermo=False) + arc8 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + sp_level='method/unsupported', calc_freq_factor=False, compute_thermo=False) self.assertEqual(arc8.sp_level.simple(), 'method/unsupported') self.assertEqual(arc8.freq_level.simple(), 'wb97xd/def2tzvp') # Test that a level not supported by Arkane does raise an error if compute_thermo is True (default) with self.assertRaises(ValueError): - ARC(project='test', sp_level='method/unsupported', calc_freq_factor=False) + ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + sp_level='method/unsupported', calc_freq_factor=False) # Test dictionary format specification with auxiliary basis and DFT dispersion - arc9 = ARC(project='test', opt_level={}, + arc9 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + opt_level={}, freq_level={'method': 'B3LYP/G', 'basis': 'cc-pVDZ(fi/sf/fw)', 'auxiliary_basis': 'def2-svp/C', 'dispersion': 'DEF2-tzvp/c'}, sp_level={'method': 'DLPNO-CCSD(T)-F12', 'basis': 'cc-pVTZ-F12', @@ -319,33 +349,43 @@ def test_determine_model_chemistry_for_job_types(self): 'cabs: cc-pvtz-f12-cabs, software: orca') # Test using default frequency and orbital level for composite job, also forbid rotors job - arc10 = ARC(project='test', composite_method='cbs-qb3', calc_freq_factor=False, + arc10 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + composite_method='cbs-qb3', calc_freq_factor=False, job_types={'rotors': False, 'orbitals': True}) self.assertEqual(arc10.freq_level.simple(), 'b3lyp/cbsb7') self.assertIsNone(arc10.scan_level) self.assertEqual(arc10.orbitals_level.simple(), 'b3lyp/cbsb7') # Test using specified frequency, scan, and orbital for composite job - arc11 = ARC(project='test', composite_method='cbs-qb3', freq_level='wb97xd/6-311g', scan_level='apfd/def2svp', + arc11 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + composite_method='cbs-qb3', freq_level='wb97xd/6-311g', scan_level='apfd/def2svp', orbitals_level='hf/sto-3g', job_types={'orbitals': True}, calc_freq_factor=False) self.assertEqual(arc11.scan_level.simple(), 'apfd/def2svp') self.assertEqual(arc11.freq_level.simple(), 'wb97xd/6-311g') self.assertEqual(arc11.orbitals_level.simple(), 'hf/sto-3g') # Test using default frequency and orbital level for job specified from level of theory, also forbid rotors job - arc12 = ARC(project='test', level_of_theory='b3lyp/sto-3g', calc_freq_factor=False, + arc12 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + level_of_theory='b3lyp/sto-3g', calc_freq_factor=False, job_types={'rotors': False, 'orbitals': True}, compute_thermo=False) self.assertIsNone(arc12.scan_level) self.assertEqual(arc12.freq_level.simple(), 'b3lyp/sto-3g') self.assertEqual(arc12.orbitals_level.simple(), 'wb97x-d3/def2tzvp') # Test using specified scan level - arc13 = ARC(project='test', level_of_theory='b3lyp/sto-3g', calc_freq_factor=False, scan_level='apfd/def2svp', + arc13 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + level_of_theory='b3lyp/sto-3g', calc_freq_factor=False, scan_level='apfd/def2svp', job_types={'rotors': True}, compute_thermo=False) self.assertEqual(arc13.scan_level.simple(), 'apfd/def2svp') # Test specifying semi-empirical and force-field methods using dictionary - arc14 = ARC(project='test', opt_level={'method': 'AM1'}, freq_level={'method': 'PM6'}, + arc14 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), + opt_level={'method': 'AM1'}, freq_level={'method': 'PM6'}, sp_level={'method': 'AMBER'}, calc_freq_factor=False, compute_thermo=False) self.assertEqual(arc14.opt_level.simple(), 'am1') self.assertEqual(arc14.freq_level.simple(), 'pm6') @@ -353,6 +393,7 @@ def test_determine_model_chemistry_for_job_types(self): # Test explicit year in arkane_level_of_theory dictionary arc15 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), sp_level='wb97xd/def2tzvp', opt_level='wb97xd/def2tzvp', arkane_level_of_theory={'method': 'wb97xd', 'basis': 'def2tzvp', 'year': 2023}, @@ -362,6 +403,7 @@ def test_determine_model_chemistry_for_job_types(self): # Test warning when year is specified on sp_level instead of arkane_level_of_theory arc16 = ARC(project='test', + project_directory=os.path.join(self.scratch_dir, 'test'), sp_level={'method': 'wb97xd', 'basis': 'def2tzvp', 'year': 2023}, opt_level='wb97xd/def2tzvp', calc_freq_factor=False, compute_thermo=False) @@ -374,7 +416,9 @@ def test_determine_unique_species_labels(self): spc0 = ARCSpecies(label='spc0', smiles='CC', compute_thermo=False) spc1 = ARCSpecies(label='spc1', smiles='CC', compute_thermo=False) spc2 = ARCSpecies(label='spc2', smiles='CC', compute_thermo=False) - arc0 = ARC(project='arc_test', job_types=self.job_types1, species=[spc0, spc1, spc2], + arc0 = ARC(project='arc_test', + project_directory=os.path.join(self.scratch_dir, 'arc_test'), + job_types=self.job_types1, species=[spc0, spc1, spc2], level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)') self.assertEqual(arc0.unique_species_labels, ['spc0', 'spc1', 'spc2']) spc3 = ARCSpecies(label='spc0', smiles='CC', compute_thermo=False) @@ -385,13 +429,17 @@ def test_determine_unique_species_labels(self): def test_add_hydrogen_for_bde(self): """Test the add_hydrogen_for_bde method""" spc0 = ARCSpecies(label='spc0', smiles='CC', compute_thermo=False) - arc0 = ARC(project='arc_test', job_types=self.job_types1, species=[spc0], + arc0 = ARC(project='arc_test', + project_directory=os.path.join(self.scratch_dir, 'arc_test'), + job_types=self.job_types1, species=[spc0], level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)') arc0.add_hydrogen_for_bde() self.assertEqual(len(arc0.species), 1) spc1 = ARCSpecies(label='spc1', smiles='CC', compute_thermo=False, bdes=['all_h']) - arc1 = ARC(project='arc_test', job_types=self.job_types1, species=[spc1], + arc1 = ARC(project='arc_test', + project_directory=os.path.join(self.scratch_dir, 'arc_test'), + job_types=self.job_types1, species=[spc1], level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)') arc1.add_hydrogen_for_bde() self.assertEqual(len(arc1.species), 2) @@ -428,7 +476,9 @@ def test_process_adaptive_levels(self): self.assertEqual(processed_2[(1, 'inf')][('sp',)].simple(), 'b3lyp/6-311+g(d,p)') # Restart round-trip: as_dict() must emit the list form and reproduce the same structure. - arc0 = ARC(project='adaptive_levels_test', adaptive_levels=adaptive_levels_1) + arc0 = ARC(project='adaptive_levels_test', + project_directory=os.path.join(self.scratch_dir, 'adaptive_levels_test'), + adaptive_levels=adaptive_levels_1) restart_levels = arc0.as_dict()['adaptive_levels'] self.assertIsInstance(restart_levels, list) reprocessed = process_adaptive_levels(restart_levels) @@ -473,16 +523,22 @@ def test_process_level_of_theory(self): """ Tests the process_level_of_theory function. """ - arc0 = ARC(project='test_0', level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)', + arc0 = ARC(project='test_0', + project_directory=os.path.join(self.scratch_dir, 'test_0'), + level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)', bac_type=None, freq_scale_factor=1) - arc1 = ARC(project='test_1', level_of_theory='wb97xd/6-311+g(2d,2p)', + arc1 = ARC(project='test_1', + project_directory=os.path.join(self.scratch_dir, 'test_1'), + level_of_theory='wb97xd/6-311+g(2d,2p)', arkane_level_of_theory="b3lyp/6-311+g(3df,2p)", bac_type=None, freq_scale_factor=1, job_types={"freq": True, "sp": True, "opt": False}) - arc2 = ARC(project='test_2', sp_level='wb97xd/6-311+g(2d,2p)', + arc2 = ARC(project='test_2', + project_directory=os.path.join(self.scratch_dir, 'test_2'), + sp_level='wb97xd/6-311+g(2d,2p)', opt_level='wb97xd/6-311+g(2d,2p)', arkane_level_of_theory="b3lyp/6-311+g(3df,2p)", bac_type=None, @@ -490,7 +546,9 @@ def test_process_level_of_theory(self): job_types={"freq": True, "sp": False, "opt": False}) - arc3 = ARC(project='test_3', sp_level='wb97xd/6-311+g(2d,2p)', + arc3 = ARC(project='test_3', + project_directory=os.path.join(self.scratch_dir, 'test_3'), + sp_level='wb97xd/6-311+g(2d,2p)', opt_level='wb97xd/6-311+g(2d,2p)', arkane_level_of_theory="b3lyp/6-311+g(3df,2p)", bac_type=None, @@ -513,25 +571,13 @@ def test_unknown_ts_adapter(self): ) with self.assertRaises(InputError): arc0 = ARC(project='arc_test', + project_directory=os.path.join(self.scratch_dir, 'arc_test'), job_types=self.job_types1, species=[spc1], level_of_theory='ccsd(t)-f12/cc-pvdz-f12//b3lyp/6-311+g(3df,2p)', ts_adapters=['WRONG ADAPTER', 'AutoTST', 'GCN', 'xtb_gsm'], ) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests - """ - projects = ['arc_project_for_testing_delete_after_usage_test_from_dict', - 'arc_model_chemistry_test', 'arc_test', 'test', 'unit_test_specific_job', 'wrong'] - for project in projects: - project_directory = os.path.join(ARC_PATH, 'Projects', project) - if os.path.isdir(project_directory): - shutil.rmtree(project_directory, ignore_errors=True) - class TestCheckFileCleanup(unittest.TestCase): """ diff --git a/arc/plotter_test.py b/arc/plotter_test.py index ba6984dae4..78a62b6c92 100644 --- a/arc/plotter_test.py +++ b/arc/plotter_test.py @@ -7,10 +7,11 @@ import os import shutil +import tempfile import unittest import arc.plotter as plotter -from arc.common import ARC_PATH, ARC_TESTING_PATH, read_yaml_file, safe_copy_file +from arc.common import ARC_TESTING_PATH, read_yaml_file, safe_copy_file from arc.species.converter import str_to_xyz from arc.species.species import ARCSpecies @@ -20,6 +21,12 @@ class TestPlotter(unittest.TestCase): Contains unit tests for the parser functions """ + def setUp(self): + """A method that is run before each unit test in this class.""" + self.scratch_dir = tempfile.mkdtemp(prefix='arc_test_plotter_') + self.addCleanup(shutil.rmtree, self.scratch_dir, ignore_errors=True) + self.project_directory = os.path.join(self.scratch_dir, 'arc_project_for_testing_delete_after_usage') + def test_save_geo(self): """Test saving the geometry files for a species""" spc = ARCSpecies(label='methylamine', smiles='CN', multiplicity=1, charge=0) @@ -31,8 +38,7 @@ def test_save_geo(self): H -1.16115119 0.31478894 0.81506145 H -1.16115119 0.31478894 -0.81506145""") spc.opt_level = 'opt/level' - project = 'arc_project_for_testing_delete_after_usage' - project_directory = os.path.join(ARC_PATH, 'Projects', project) + project_directory = self.project_directory xyz_path = os.path.join(project_directory, 'output', 'Species', spc.label, 'geometry', 'methylamine.xyz') gjf_path = os.path.join(project_directory, 'output', 'Species', spc.label, 'geometry', 'methylamine.gjf') plotter.save_geo(species=spc, project_directory=project_directory) @@ -68,8 +74,7 @@ def test_save_geo(self): def test_augment_arkane_yml_file_with_mol_repr(self): """Test the augment_arkane_yml_file_with_mol_repr() function""" - project = 'arc_project_for_testing_delete_after_usage' - project_directory = os.path.join(ARC_PATH, 'Projects', project) + project_directory = self.project_directory n4h6_yml_path = os.path.join(ARC_TESTING_PATH, 'yml_testing', 'N4H6.yml') n4h6_yml_path_copy = os.path.join(project_directory, 'Species', 'N4H6', 'N4H6.yml') os.makedirs(os.path.join(project_directory, 'Species', 'N4H6'), exist_ok=True) @@ -83,8 +88,7 @@ def test_augment_arkane_yml_file_with_mol_repr(self): def test_save_conformers_file(self): """test the save_conformers_file function""" - project = 'arc_project_for_testing_delete_after_usage' - project_directory = os.path.join(ARC_PATH, 'Projects', project) + project_directory = self.project_directory label = 'butanol' spc1 = ARCSpecies(label=label, smiles='CCCCO') spc1.generate_conformers(n_confs=3) @@ -100,11 +104,10 @@ def test_save_conformers_file(self): def test_save_rotor_text_file(self): """Test the save_rotor_text_file function""" - project = 'arc_project_for_testing_delete_after_usage' angles = [0, 90, 180, 270, 360] energies = [0, 10, 0, 10, 0] pivots = [1, 2] - path = os.path.join(ARC_PATH, 'Projects', project, 'rotors', '{0}_directed_scan.txt'.format(pivots)) + path = os.path.join(self.project_directory, 'rotors', '{0}_directed_scan.txt'.format(pivots)) plotter.save_rotor_text_file(angles, energies, path) self.assertTrue(os.path.isfile(path)) with open(path, 'r') as f: @@ -113,7 +116,7 @@ def test_save_rotor_text_file(self): def test_log_bde_report(self): """Test the log_bde_report() function""" - path = os.path.join(ARC_TESTING_PATH, 'bde_report_test.txt') + path = os.path.join(self.scratch_dir, 'bde_report_test.txt') bde_report = {'aniline': {(1, 2): 431.43, (5, 8): 465.36, (6, 9): 458.70, (3, 10): 463.16, (4, 11): 463.16, (7, 12): 458.70, (1, 13): 372.31, (1, 14): 372.31, (5, 6): 'N/A'}} xyz = """N 2.28116100 -0.20275000 -0.29653100 @@ -178,63 +181,51 @@ def test_clean_scan_results(self): def test_make_multi_species_output_file(self): """Test the make_multi_species_output_file function""" # The xyzs used in the ARCSpecies are dummy xyzs, they are not the actual xyzs used in the output file + path = os.path.join(self.scratch_dir, 'mltspc_output.out') + safe_copy_file(source=os.path.join(ARC_TESTING_PATH, 'mltspc_output.out'), destination=path) plotter.make_multi_species_output_file(species_list=[ARCSpecies(label='water', smiles='O', multi_species='mltspc1'), ARCSpecies(label='acetylene', smiles='C#C', multi_species='mltspc1'), ARCSpecies(label='N-Valeric_Acid', smiles='CCCCC(O)=O', multi_species='mltspc1')], label='mltspc1', - path=os.path.join(ARC_TESTING_PATH, 'mltspc_output.out'), + path=path, ) - self.assertTrue(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'water.log'))) - self.assertTrue(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'acetylene.log'))) - self.assertTrue(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'N-Valeric_Acid.log'))) + self.assertTrue(os.path.isfile(os.path.join(self.scratch_dir, 'water.log'))) + self.assertTrue(os.path.isfile(os.path.join(self.scratch_dir, 'acetylene.log'))) + self.assertTrue(os.path.isfile(os.path.join(self.scratch_dir, 'N-Valeric_Acid.log'))) def test_delete_multi_species_output_file(self): """Test the delete_multi_species_output_file function""" # The xyzs used in the ARCSpecies are dummy xyzs, they are not the actual xyzs used in the output file + path = os.path.join(self.scratch_dir, 'mltspc_output.out') + safe_copy_file(source=os.path.join(ARC_TESTING_PATH, 'mltspc_output.out'), destination=path) species_list = [ARCSpecies(label='water', smiles='O', multi_species='mltspc1'), ARCSpecies(label='acetylene', smiles='C#C', multi_species='mltspc1'), ARCSpecies(label='N-Valeric_Acid', smiles='CCCCC(O)=O', multi_species='mltspc1')] multi_species_path_dict = plotter.make_multi_species_output_file(species_list=species_list, label='mltspc1', - path=os.path.join(ARC_TESTING_PATH, 'mltspc_output.out'), + path=path, ) - self.assertTrue(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'water.log'))) - self.assertTrue(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'acetylene.log'))) - self.assertTrue(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'N-Valeric_Acid.log'))) + self.assertTrue(os.path.isfile(os.path.join(self.scratch_dir, 'water.log'))) + self.assertTrue(os.path.isfile(os.path.join(self.scratch_dir, 'acetylene.log'))) + self.assertTrue(os.path.isfile(os.path.join(self.scratch_dir, 'N-Valeric_Acid.log'))) plotter.delete_multi_species_output_file(species_list=species_list, label='mltspc1', multi_species_path_dict=multi_species_path_dict, ) - self.assertFalse(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'water.log'))) - self.assertFalse(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'acetylene.log'))) - self.assertFalse(os.path.isfile(os.path.join(ARC_TESTING_PATH, 'N-Valeric_Acid.log'))) + self.assertFalse(os.path.isfile(os.path.join(self.scratch_dir, 'water.log'))) + self.assertFalse(os.path.isfile(os.path.join(self.scratch_dir, 'acetylene.log'))) + self.assertFalse(os.path.isfile(os.path.join(self.scratch_dir, 'N-Valeric_Acid.log'))) def test_save_irc_traj_animation(self): """Test the save_irc_traj_animation function""" irc_f_path = os.path.join(ARC_TESTING_PATH, 'irc', 'rxn_1_irc_1.out') irc_r_path = os.path.join(ARC_TESTING_PATH, 'irc', 'rxn_1_irc_2.out') - out_path = os.path.join(ARC_TESTING_PATH, 'irc', 'rxn_1_irc_animation.out') + out_path = os.path.join(self.scratch_dir, 'irc', 'rxn_1_irc_animation.out') + os.makedirs(os.path.dirname(out_path), exist_ok=True) self.assertFalse(os.path.isfile(out_path)) plotter.save_irc_traj_animation(irc_f_path, irc_r_path, out_path) self.assertTrue(os.path.isfile(out_path)) - @classmethod - def tearDownClass(cls): - """A function that is run ONCE after all unit tests in this class.""" - project = 'arc_project_for_testing_delete_after_usage' - project_directory = os.path.join(ARC_PATH, 'Projects', project) - shutil.rmtree(project_directory, ignore_errors=True) - files_to_remove = [os.path.join(ARC_TESTING_PATH, 'bde_report_test.txt'), - os.path.join(ARC_TESTING_PATH, 'water.log'), - os.path.join(ARC_TESTING_PATH, 'acetylene.log'), - os.path.join(ARC_TESTING_PATH, 'N-Valeric_Acid.log'), - os.path.join(ARC_TESTING_PATH, 'irc', 'rxn_1_irc_animation.out'), - ] - for file_path in files_to_remove: - if os.path.isfile(file_path): - os.remove(file_path) - - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/processor_test.py b/arc/processor_test.py index cdbaced736..cb35c0439a 100644 --- a/arc/processor_test.py +++ b/arc/processor_test.py @@ -7,11 +7,12 @@ import os import shutil +import tempfile import unittest import arc.processor as processor from arc.checks.common import TS_IRC_FAILED_MARKER -from arc.common import ARC_TESTING_PATH, read_yaml_file +from arc.common import read_yaml_file from arc.reaction import ARCReaction from arc.species import ARCSpecies @@ -27,6 +28,8 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.maxDiff = None + cls.scratch_dir = tempfile.mkdtemp(prefix='arc_test_processor_') + cls.addClassCleanup(shutil.rmtree, cls.scratch_dir, ignore_errors=True) cls.ch4 = ARCSpecies(label='CH4', smiles='C') cls.nh3 = ARCSpecies(label='NH3', smiles='N') cls.h = ARCSpecies(label='H', smiles='[H]') @@ -57,7 +60,7 @@ def test_compare_rates(self): kinetics={'A': 7.18e5, 'n': 2.05, 'Ea': 151.88}, ) rxn_2.ts_species = ARCSpecies(label='TS2', is_ts=True) - output_directory = os.path.join(ARC_TESTING_PATH, 'process_kinetics') + output_directory = os.path.join(self.scratch_dir, 'process_kinetics') reactions_to_compare = processor.compare_rates(rxns_for_kinetics_lib=[rxn_1, rxn_2], output_directory=output_directory, ) @@ -72,17 +75,5 @@ def test_compare_rates(self): self.assertNotIn('ts_validation', content[1]) - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - """ - directories = [os.path.join(ARC_TESTING_PATH, 'process_kinetics'), - ] - for dir_path in directories: - if os.path.isdir(dir_path): - shutil.rmtree(dir_path) - - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arc/reaction/reaction_test.py b/arc/reaction/reaction_test.py index 81f31d3628..bf245d2915 100644 --- a/arc/reaction/reaction_test.py +++ b/arc/reaction/reaction_test.py @@ -8,6 +8,7 @@ from itertools import permutations import os import shutil +import tempfile import time import unittest @@ -1048,7 +1049,9 @@ def test_multi_reactants(self): def test_load_ts_xyz_user_guess_from_files(self): """Test various loading a reaction and populating the TS ARCSpecies with user xyz guesses from files""" - project_directory = os.path.join(ARC_TESTING_PATH, 'reactions', 'methanoate_hydrolysis') + project_directory = os.path.join(tempfile.mkdtemp(prefix='arc_test_reaction_'), 'methanoate_hydrolysis') + self.addCleanup(shutil.rmtree, os.path.dirname(project_directory), ignore_errors=True) + shutil.copytree(os.path.join(ARC_TESTING_PATH, 'reactions', 'methanoate_hydrolysis'), project_directory) input_dict = read_yaml_file(path=os.path.join(project_directory, 'input_1.yml')) input_dict['project_directory'] = project_directory arc_object = ARC(**input_dict) @@ -1124,15 +1127,6 @@ def test_atom_map_property(self): @classmethod def tearDownClass(cls): """A function that is run ONCE after all unit tests in this class.""" - project_directory = os.path.join(ARC_TESTING_PATH, 'reactions', 'methanoate_hydrolysis') - sub_folders = ['log_and_restart_archive', 'output'] - files_to_remove = ['arc.log'] - for sub_folder in sub_folders: - shutil.rmtree(os.path.join(project_directory, sub_folder), ignore_errors=True) - for file_path in files_to_remove: - full_file_path = os.path.join(project_directory, file_path) - if os.path.isfile(full_file_path): - os.remove(full_file_path) file_paths = [os.path.join(ARC_PATH, 'arc', 'reaction', 'nul'), os.path.join(ARC_PATH, 'arc', 'reaction', 'run.out')] for file_path in file_paths: if os.path.isfile(file_path): diff --git a/arc/species/species_test.py b/arc/species/species_test.py index ef48c7efc3..9e20059448 100644 --- a/arc/species/species_test.py +++ b/arc/species/species_test.py @@ -1821,7 +1821,8 @@ def test_preserving_multiplicity(self): def test_append_conformers(self): """Test that ARC correctly parses its own conformer files""" - project_directory = os.path.join(ARC_PATH, 'Projects', 'arc_project_for_testing_delete_after_usage4') + project_directory = tempfile.mkdtemp(prefix='arc_test_species_conformers_') + self.addCleanup(shutil.rmtree, project_directory, ignore_errors=True) xyzs = [{'symbols': ('O', 'C', 'C', 'H', 'H', 'H'), 'isotopes': (16, 12, 12, 1, 1, 1), 'coords': ((1.090687, 0.265168, -0.167063), (2.922041, -1.183357, -0.388849), (2.276555, -0.003739, 0.085435), (2.365448, -1.88781, -0.999146), @@ -3348,14 +3349,8 @@ def test_rmg_mol_to_dict_repr(self): def tearDownClass(cls): """ A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests + Delete files created during these unit tests """ - projects = ['arc_project_for_testing_delete_after_usage4', - os.path.join(ARC_TESTING_PATH, 'gcn_tst')] - for project in projects: - project_directory = os.path.join(ARC_PATH, 'Projects', project) - shutil.rmtree(project_directory, ignore_errors=True) - file_paths = [os.path.join(ARC_PATH, 'nul'), os.path.join(ARC_PATH, 'run.out'), os.path.join(ARC_PATH, 'arc', 'species', 'nul'), os.path.join(ARC_PATH, 'arc', 'species', 'run.out')] for file_path in file_paths: diff --git a/arc/statmech/arkane_test.py b/arc/statmech/arkane_test.py index ffaf90827e..82a642f195 100644 --- a/arc/statmech/arkane_test.py +++ b/arc/statmech/arkane_test.py @@ -67,6 +67,7 @@ def setUpClass(cls): A method that is run before all unit tests in this class. """ cls.tmpdir = tempfile.mkdtemp(prefix='test_Arkane_') + cls.addClassCleanup(shutil.rmtree, cls.tmpdir, ignore_errors=True) output_path_1 = os.path.join(cls.tmpdir, 'output_1') calcs_path_1 = os.path.join(cls.tmpdir, 'calcs_1') output_path_2 = os.path.join(cls.tmpdir, 'output_2') @@ -390,7 +391,7 @@ def test_warn_no_match_logs(self): def test_generate_arkane_input(self): """Test generating Arkane input""" - statmech_dir = os.path.join(ARC_TESTING_PATH, 'arkane_input_tests_delete') + statmech_dir = os.path.join(self.tmpdir, 'arkane_input_tests_delete') os.makedirs(statmech_dir, exist_ok=True) self.arkane_1.generate_arkane_input(statmech_dir=statmech_dir) input_path = os.path.join(statmech_dir, 'input.py') @@ -426,14 +427,6 @@ def test_lone_pair_species_uses_adjacency_list(self): self.assertNotIn("SMILES('[CH2]')", content) # must NOT use the lossy SMILES self.assertIn("structure=SMILES('O')", content) # normal species unchanged - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - """ - shutil.rmtree(cls.tmpdir, ignore_errors=True) - shutil.rmtree(os.path.join(ARC_TESTING_PATH, 'arkane_input_tests_delete'), ignore_errors=True) - class TestArkaneOutputParsing(unittest.TestCase): """Tests for parsing functions that read Arkane output.py content.""" diff --git a/arc/utils/scale_test.py b/arc/utils/scale_test.py index fb8f1b9602..cc53d1500d 100644 --- a/arc/utils/scale_test.py +++ b/arc/utils/scale_test.py @@ -7,9 +7,10 @@ import os import shutil +import tempfile import unittest -from arc.common import almost_equal_coords_lists, ARC_PATH +from arc.common import almost_equal_coords_lists from arc.level import Level from arc.utils.scale import (calculate_truhlar_scaling_factors, get_species_list, @@ -71,7 +72,8 @@ def test_summarize_results(self): ] times = ['3', '5'] overall_time = '8.5' - base_path = os.path.join(ARC_PATH, 'Projects', 'scaling_factors_arc_testing_delete_after_usage') + base_path = tempfile.mkdtemp(prefix='arc_test_scaling_factors_') + self.addCleanup(shutil.rmtree, base_path, ignore_errors=True) summarize_results(lambda_zpes=lambda_zpes, levels=levels_of_theory, @@ -120,15 +122,6 @@ def test_rename_level(self): self.assertEqual(renamed_level2, 'wb97xd_6-311pGb2d,2pb') self.assertEqual(renamed_level3, 'wb97xd_aug-ccpZQZ,_solvation_method.._SMD,_solvent.._DMSO,_software.._gaussian') - @classmethod - def tearDownClass(cls): - """ - A function that is run ONCE after all unit tests in this class. - Delete all directories created during these unit tests - """ - path = os.path.join(ARC_PATH, 'Projects', 'scaling_factors_arc_testing_delete_after_usage') - shutil.rmtree(path, ignore_errors=True) - if __name__ == '__main__': unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/functional/restart_test.py b/functional/restart_test.py index 35594910b8..30cba1d290 100644 --- a/functional/restart_test.py +++ b/functional/restart_test.py @@ -7,6 +7,7 @@ import os import shutil +import tempfile import unittest import warnings @@ -16,14 +17,6 @@ from arc.main import ARC -def _project_name(base: str) -> str: - """Return a per-xdist-worker project name to avoid parallel cleanup collisions.""" - worker_id = os.environ.get('PYTEST_XDIST_WORKER') - if worker_id: - return f'{base}_{worker_id}' - return base - - class TestRestart(unittest.TestCase): """ Contains unit tests for restarting ARC. @@ -37,6 +30,12 @@ def setUpClass(cls): cls.maxDiff = None warnings.filterwarnings(action='ignore', module='.*matplotlib.*') + def make_project_directory(self, project: str) -> str: + """Get a path to a temporary project directory that is deleted when the test ends.""" + project_directory = os.path.join(tempfile.mkdtemp(prefix='arc_test_restart_'), project) + self.addCleanup(shutil.rmtree, os.path.dirname(project_directory), ignore_errors=True) + return project_directory + def test_restart_thermo(self): """ Test restarting ARC through the ARC class in main.py via the input_dict argument of the API @@ -44,8 +43,8 @@ def test_restart_thermo(self): """ restart_dir = os.path.join(ARC_PATH, 'arc', 'testing', 'restart', '1_restart_thermo') restart_path = os.path.join(restart_dir, 'restart.yml') - project = _project_name('arc_project_for_testing_delete_after_usage_restart_thermo') - project_directory = os.path.join(ARC_PATH, 'Projects', project) + project = 'arc_project_for_testing_delete_after_usage_restart_thermo' + project_directory = self.make_project_directory(project) os.makedirs(os.path.dirname(project_directory), exist_ok=True) shutil.copytree(os.path.join(restart_dir, 'calcs'), os.path.join(project_directory, 'calcs', 'Species'), dirs_exist_ok=True) input_dict = read_yaml_file(path=restart_path, project_directory=project_directory) @@ -141,8 +140,8 @@ def test_restart_rate_1(self): """Test restarting ARC and attaining a reaction rate coefficient""" restart_dir = os.path.join(ARC_PATH, 'arc', 'testing', 'restart', '2_restart_rate') restart_path = os.path.join(restart_dir, 'restart.yml') - project = _project_name('arc_project_for_testing_delete_after_usage_restart_rate_1') - project_directory = os.path.join(ARC_PATH, 'Projects', project) + project = 'arc_project_for_testing_delete_after_usage_restart_rate_1' + project_directory = self.make_project_directory(project) os.makedirs(os.path.dirname(project_directory), exist_ok=True) shutil.copytree(os.path.join(restart_dir, 'calcs'), os.path.join(project_directory, 'calcs'), dirs_exist_ok=True) input_dict = read_yaml_file(path=restart_path, project_directory=project_directory) @@ -162,8 +161,8 @@ def test_restart_rate_1(self): def test_restart_rate_2(self): """Test restarting ARC and attaining a reaction rate coefficient""" - project = _project_name('arc_project_for_testing_delete_after_usage_restart_rate_2') - project_directory = os.path.join(ARC_PATH, 'Projects', project) + project = 'arc_project_for_testing_delete_after_usage_restart_rate_2' + project_directory = self.make_project_directory(project) base_path = os.path.join(ARC_PATH, 'arc', 'testing', 'restart', '5_TS1') restart_path = os.path.join(base_path, 'restart.yml') input_dict = read_yaml_file(path=restart_path, project_directory=project_directory) @@ -191,8 +190,8 @@ def test_restart_bde (self): """Test restarting ARC and attaining a BDE for anilino_radical.""" restart_dir = os.path.join(ARC_PATH, 'arc', 'testing', 'restart', '3_restart_bde') restart_path = os.path.join(restart_dir, 'restart.yml') - project = _project_name('test_restart_bde') - project_directory = os.path.join(ARC_PATH, 'Projects', project) + project = 'test_restart_bde' + project_directory = self.make_project_directory(project) os.makedirs(os.path.dirname(project_directory), exist_ok=True) shutil.copytree(os.path.join(restart_dir, 'calcs'), os.path.join(project_directory, 'calcs'), dirs_exist_ok=True) input_dict = read_yaml_file(path=restart_path, project_directory=project_directory) @@ -200,7 +199,7 @@ def test_restart_bde (self): arc1 = ARC(**input_dict) arc1.execute() - report_path = os.path.join(ARC_PATH, 'Projects', project, 'output', 'BDE_report.txt') + report_path = os.path.join(project_directory, 'output', 'BDE_report.txt') with open(report_path, 'r') as f: lines = f.readlines() self.assertIn(' BDE report for anilino_radical:\n', lines) @@ -224,17 +223,8 @@ def test_globalize_paths(self): def tearDownClass(cls): """ A function that is run ONCE after all unit tests in this class. - Delete all project directories created during these unit tests + Delete all files and directories created during these unit tests """ - projects = [_project_name('arc_project_for_testing_delete_after_usage_restart_thermo'), - _project_name('arc_project_for_testing_delete_after_usage_restart_rate_1'), - _project_name('arc_project_for_testing_delete_after_usage_restart_rate_2'), - _project_name('test_restart_bde'), - ] - for project in projects: - project_directory = os.path.join(ARC_PATH, 'Projects', project) - shutil.rmtree(project_directory, ignore_errors=True) - shutil.rmtree(os.path.join(ARC_PATH, 'arc', 'testing', 'restart', '4_globalized_paths', 'log_and_restart_archive'), ignore_errors=True) for file_name in ['arc.log', 'restart_paths_globalized.yml']: