Repository: Quantum-Accelerators/quacc
Pull request #2238 (2024-06-12 03:53:10)

Refactor the runners some more


Patch:
diff --git a/src/quacc/runners/_base.py b/src/quacc/runners/_base.py
index 8d53225e..cdd44daf 100644
--- a/src/quacc/runners/_base.py
+++ b/src/quacc/runners/_base.py
@@ -4,6 +4,7 @@ Base class for runners.
 
 from __future__ import annotations
 
+from dataclasses import dataclass
 from typing import TYPE_CHECKING
 
 from quacc.runners.prep import calc_cleanup, calc_setup
@@ -14,39 +15,37 @@ if TYPE_CHECKING:
     from quacc.utils.files import Filenames, SourceDirectory
 
 
+@dataclass
 class BaseRunner:
     """
     A base class for runners that sets up the calculation and cleans up the scratch directory.
+
+    Attributes
+    ----------
+    atoms
+        Atoms object with calculator attached (or no Atoms object at all).
+    copy_files
+        Files to copy to runtime directory.
     """
 
-    def __init__(
-        self,
-        atoms: Atoms | None,
-        copy_files: SourceDirectory | dict[SourceDirectory, Filenames] | None = None,
-    ) -> None:
-        """
-        Initialize the BaseRunner.
+    atoms: Atoms | None = None
+    copy_files: SourceDirectory | dict[SourceDirectory, Filenames] | None = None
 
-        Parameters
-        ----------
-        atoms
-            The atoms object
-        copy_files
-            The files to copy to the scratch directory
+    def setup(self) -> None:
+        """
+        Perform setup operations on the runtime directory.
 
         Returns
         -------
         None
         """
-        self.atoms = atoms
-        self.copy_files = copy_files
         self.tmpdir, self.job_results_dir = calc_setup(
             self.atoms, copy_files=self.copy_files
         )
 
     def cleanup(self) -> None:
         """
-        Perform cleanup operations on the scratch directory.
+        Perform cleanup operations on the runtime directory.
 
         Returns
         -------
diff --git a/src/quacc/runners/ase.py b/src/quacc/runners/ase.py
index c3e47b54..6af8698b 100644
--- a/src/quacc/runners/ase.py
+++ b/src/quacc/runners/ase.py
@@ -94,9 +94,10 @@ class Runner(BaseRunner):
         -------
         None
         """
-        atoms = copy_atoms(atoms)
-        atoms.calc = calculator
-        super().__init__(atoms, copy_files=copy_files)
+        self.atoms = copy_atoms(atoms)
+        self.atoms.calc = calculator
+        self.copy_files = copy_files
+        self.setup()
 
     def run_calc(
         self, geom_file: str | None = None, properties: list[str] | None = None
diff --git a/src/quacc/runners/phonons.py b/src/quacc/runners/phonons.py
index bde417e8..552416f5 100644
--- a/src/quacc/runners/phonons.py
+++ b/src/quacc/runners/phonons.py
@@ -20,8 +20,15 @@ if TYPE_CHECKING:
 
 
 class PhonopyRunner(BaseRunner):
-    def __init__(self):
-        super().__init__(atoms=None)
+    def __init__(self) -> None:
+        """
+        Initialize the PhonopyRunner.
+
+        Returns
+        -------
+        None
+        """
+        self.setup()
 
     @requires(has_phonopy, "Phonopy is not installed.")
     @requires(has_seekpath, "Seekpath is not installed")


Test patch:
diff --git a/tests/core/runners/test_ase.py b/tests/core/runners/test_ase.py
index c3f62442..0cb2f31a 100644
--- a/tests/core/runners/test_ase.py
+++ b/tests/core/runners/test_ase.py
@@ -16,6 +16,7 @@ from ase.optimize import BFGS, BFGSLineSearch
 from ase.optimize.sciopt import SciPyFminBFGS
 
 from quacc import SETTINGS, change_settings
+from quacc.runners._base import BaseRunner
 from quacc.runners.ase import Runner
 
 LOGGER = logging.getLogger(__name__)
@@ -46,6 +47,40 @@ def teardown_function():
             os.remove(os.path.join(SETTINGS.RESULTS_DIR, f))
 
 
+def test_base_runner(tmp_path, monkeypatch):
+    monkeypatch.chdir(tmp_path)
+    atoms = bulk("Cu")
+    atoms.calc = EMT()
+    br = BaseRunner(atoms)
+
+    br.setup()
+    assert "tmp" in str(br.tmpdir)
+    assert br.tmpdir.exists()
+    assert "tmp" not in str(br.job_results_dir)
+    assert not br.job_results_dir.exists()
+    assert Path(br.atoms.calc.directory) == br.tmpdir
+
+    br.cleanup()
+    assert not br.tmpdir.exists()
+    assert br.job_results_dir.exists()
+    assert Path(br.atoms.calc.directory) == br.job_results_dir
+
+
+def test_base_runner2(tmp_path, monkeypatch):
+    monkeypatch.chdir(tmp_path)
+    br = BaseRunner()
+
+    br.setup()
+    assert "tmp" in str(br.tmpdir)
+    assert br.tmpdir.exists()
+    assert "tmp" not in str(br.job_results_dir)
+    assert not br.job_results_dir.exists()
+
+    br.cleanup()
+    assert not br.tmpdir.exists()
+    assert br.job_results_dir.exists()
+
+
 def test_run_calc(tmp_path, monkeypatch):
     monkeypatch.chdir(tmp_path)