Repository: popsim-consortium/stdpopsim (language: python)

Issue:
Check minimum supported version of SLiM at run time
We need to check that SLiM is at least version X when we try to use the SLiM Engine, or the user will get cryptic errors.

I think the minimum is 3.5 now, after the transition to msprime 1.


Discussion / hints:

Fix patch:
diff --git a/stdpopsim/slim_engine.py b/stdpopsim/slim_engine.py
index b7bde9800..f322e139c 100644
--- a/stdpopsim/slim_engine.py
+++ b/stdpopsim/slim_engine.py
@@ -1007,10 +1007,23 @@ class _SLiMEngine(stdpopsim.Engine):
     def slim_path(self):
         return os.environ.get("SLIM", "slim")
 
-    def get_version(self):
-        s = subprocess.check_output([self.slim_path(), "-v"])
+    def get_version(self, slim_path=None):
+        if slim_path is None:
+            slim_path = self.slim_path()
+        s = subprocess.check_output([slim_path, "-v"])
         return s.split()[2].decode("ascii").rstrip(",")
 
+    def _assert_min_version(self, min_required_version, slim_path):
+        def version_split(version):
+            return [int(v) for v in version.split(".")]
+
+        current_version = self.get_version(slim_path)
+        if version_split(current_version) < version_split(min_required_version):
+            raise RuntimeError(
+                f"Minimum supported SLiM version is {min_required_version}, "
+                f"but only found version {current_version}"
+            )
+
     def simulate(
         self,
         demographic_model,
@@ -1150,6 +1163,10 @@ def _run_slim(self, script_file, slim_path=None, seed=None, dry_run=False):
         """
         if slim_path is None:
             slim_path = self.slim_path()
+
+        # SLiM v3.5 needed with msprime 1.0
+        self._assert_min_version("3.5", slim_path)
+
         slim_cmd = [slim_path]
         if seed is not None:
             slim_cmd.extend(["-s", f"{seed}"])


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2a52b51eb..9e4312247 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -20,7 +20,7 @@ jobs:
         os: [ubuntu-18.04, windows-2019, macos-10.15]
         python: [3.7, 3.9]
     env:
-      SLIM_TAG: 3.4
+      SLIM_TAG: 3.5
       CONDA_ENV_NAME: stdpopsim
 
     steps:
diff --git a/tests/test_slim_engine.py b/tests/test_slim_engine.py
index f2581a80e..2cf3efd5c 100644
--- a/tests/test_slim_engine.py
+++ b/tests/test_slim_engine.py
@@ -196,6 +196,21 @@ def test_recap_and_rescale(self):
             self.assertEqual(tables1.edges, tables2.edges)
             self.assertEqual(tables1.mutations, tables2.mutations)
 
+    def test_assert_min_version(self):
+        engine = stdpopsim.get_engine("slim")
+        with mock.patch(
+            "stdpopsim.slim_engine._SLiMEngine.get_version", return_value="3.4"
+        ):
+            with self.assertRaises(RuntimeError):
+                engine._assert_min_version("3.5", engine.slim_path())
+            with self.assertRaises(RuntimeError):
+                engine._assert_min_version("4.0", None)
+        with mock.patch(
+            "stdpopsim.slim_engine._SLiMEngine.get_version", return_value="4.0"
+        ):
+            engine._assert_min_version("3.5", engine.slim_path())
+            engine._assert_min_version("3.6", None)
+
 
 @unittest.skipIf(IS_WINDOWS, "SLiM not available on windows")
 class TestCLI(unittest.TestCase):
@@ -255,7 +270,7 @@ def test_simulate(self):
         self.assertEqual(observed_counts[2], 8)
         self.assertTrue(all(tree.num_roots == 1 for tree in ts.trees()))
 
-    @mock.patch("stdpopsim.slim_engine._SLiMEngine.get_version", return_value="64")
+    @mock.patch("stdpopsim.slim_engine._SLiMEngine.get_version", return_value="64.64")
     def test_dry_run(self, _mocked_get_version):
         # --dry-run should run slim, but not create an output file.
         with mock.patch("subprocess.Popen", autospec=True) as mocked_popen: