Skip to content

Commit

Permalink
enable tests (this will not work)
Browse files Browse the repository at this point in the history
use tempdir, closes #427

.

temp file names

better context handling

extra level of escaping in eidos

escape logfile

cache bump

.
  • Loading branch information
petrelharp committed Mar 21, 2023
1 parent 5bb5b71 commit 5dc0c4f
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 103 deletions.
81 changes: 38 additions & 43 deletions stdpopsim/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
pass


IS_WINDOWS = sys.platform.startswith("win")

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -1040,47 +1038,44 @@ def time_or_model(
"This option may provided multiple times.",
)

# SLiM is not available for windows.
if not IS_WINDOWS:

def slim_exec(path):
# Hack to set the SLIM environment variable at parse time,
# before get_version() can be called.
os.environ["SLIM"] = path
return path

slim_parser = top_parser.add_argument_group("SLiM specific parameters")
slim_parser.add_argument(
"--slim-path",
metavar="PATH",
type=slim_exec,
default=None,
help="Full path to `slim' executable.",
)
slim_parser.add_argument(
"--slim-script",
action="store_true",
default=False,
help="Write script to stdout and exit without running SLiM.",
)
slim_parser.add_argument(
"--slim-scaling-factor",
metavar="Q",
default=1,
type=float,
help="Rescale model parameters by Q to speed up simulation. "
"See SLiM manual: `5.5 Rescaling population sizes to "
"improve simulation performance`. "
"[default=%(default)s].",
)
slim_parser.add_argument(
"--slim-burn-in",
metavar="X",
default=10,
type=float,
help="Length of the burn-in phase, in units of N generations "
"[default=%(default)s].",
)
def slim_exec(path):
# Hack to set the SLIM environment variable at parse time,
# before get_version() can be called.
os.environ["SLIM"] = path
return path

slim_parser = top_parser.add_argument_group("SLiM specific parameters")
slim_parser.add_argument(
"--slim-path",
metavar="PATH",
type=slim_exec,
default=None,
help="Full path to `slim' executable.",
)
slim_parser.add_argument(
"--slim-script",
action="store_true",
default=False,
help="Write script to stdout and exit without running SLiM.",
)
slim_parser.add_argument(
"--slim-scaling-factor",
metavar="Q",
default=1,
type=float,
help="Rescale model parameters by Q to speed up simulation. "
"See SLiM manual: `5.5 Rescaling population sizes to "
"improve simulation performance`. "
"[default=%(default)s].",
)
slim_parser.add_argument(
"--slim-burn-in",
metavar="X",
default=10,
type=float,
help="Length of the burn-in phase, in units of N generations "
"[default=%(default)s].",
)

subparsers = top_parser.add_subparsers(dest="subcommand")
subparsers.required = True
Expand Down
43 changes: 26 additions & 17 deletions stdpopsim/slim_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@

import os
import sys
import contextlib
import copy
import string
import tempfile
import subprocess
import functools
import itertools
import contextlib
import random
import textwrap
import logging
Expand All @@ -62,6 +62,12 @@

logger = logging.getLogger(__name__)


def _escape_eidos(s):
# this is for Windows paths passed as strings in Eidos
return "\\\\".join(s.split("\\"))


_slim_upper = """
initialize() {
if (!exists("dry_run"))
Expand Down Expand Up @@ -1135,7 +1141,7 @@ def fix_time(event):
recombination_rates=recomb_rates_str,
recombination_ends=recomb_ends_str,
generation_time=demographic_model.generation_time,
trees_file=trees_file,
trees_file=_escape_eidos(trees_file),
pop_names=f"c({pop_names_str})",
)
)
Expand Down Expand Up @@ -1410,7 +1416,7 @@ def matrix2str(
if logfile is not None:
printsc(
string.Template(_slim_logfile).substitute(
logfile=logfile,
logfile=_escape_eidos(str(logfile)),
loginterval=logfile_interval,
)
)
Expand Down Expand Up @@ -1552,21 +1558,27 @@ def simulate(

run_slim = not slim_script

mktemp = functools.partial(tempfile.NamedTemporaryFile, mode="w")
tempdir = tempfile.TemporaryDirectory(prefix="stdpopsim_")
ts_filename = os.path.join(tempdir.name, f"{os.urandom(3).hex()}.trees")

@contextlib.contextmanager
def script_file_f():
f = mktemp(suffix=".slim") if not slim_script else sys.stdout
yield f
if run_slim:
fname = os.path.join(tempdir.name, f"{os.urandom(3).hex()}.slim")
f = open(fname, "w")
else:
fname = "stdout"
f = sys.stdout
yield f, fname
# Don't close sys.stdout.
if not slim_script:
if run_slim:
f.close()

with script_file_f() as script_file, mktemp(suffix=".ts") as ts_file:

with script_file_f() as sf:
script_file, script_filename = sf
recap_epoch = slim_makescript(
script_file,
ts_file.name,
ts_filename,
demographic_model,
contig,
sample_sets,
Expand All @@ -1584,7 +1596,7 @@ def script_file_f():
return None

self._run_slim(
script_file.name,
script_filename,
slim_path=slim_path,
seed=seed,
dry_run=dry_run,
Expand All @@ -1594,7 +1606,7 @@ def script_file_f():
if dry_run:
return None

ts = tskit.load(ts_file.name)
ts = tskit.load(ts_filename)

ts = _add_dfes_to_metadata(ts, contig)
if _recap_and_rescale:
Expand Down Expand Up @@ -1634,8 +1646,7 @@ def _run_slim(
if slim_path is None:
slim_path = self.slim_path()

# SLiM v3.6 sends `stop()` output to stderr, which we rely upon.
self._assert_min_version("3.6", slim_path)
self._assert_min_version("4.0", slim_path)

slim_cmd = [slim_path]
if seed is not None:
Expand Down Expand Up @@ -1921,6 +1932,4 @@ def recap_and_rescale(
return ts


# SLiM does not currently work on Windows.
if sys.platform != "win32":
stdpopsim.register_engine(_SLiMEngine())
stdpopsim.register_engine(_SLiMEngine())
3 changes: 0 additions & 3 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,9 +543,6 @@ def test_gutenkunst_three_pop_ooa(self):
def test_browning_america(self):
self.verify_bad_samples("HomSap -d AmericanAdmixture_4B11 2 3 4 5 6")

IS_WINDOWS = sys.platform.startswith("win")

@pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows")
def test_browning_america_dfe(self):
self.verify_bad_samples(
"HomSap -d AmericanAdmixture_4B11 --dfe Gamma_K17 2 3 4 5 6"
Expand Down
6 changes: 0 additions & 6 deletions tests/test_dfes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
from stdpopsim import dfe
from stdpopsim import utils

IS_WINDOWS = sys.platform.startswith("win")


class TestCreateMutationType:
"""
Expand Down Expand Up @@ -554,7 +552,6 @@ def test_dfe_is_neutral(self):
)
assert d.is_neutral is (neutral and dist == "f")

@pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows")
def test_no_msprime_dfe(self):
# test we cannot simulate a non-neutral DFE with msprime
m1 = dfe.MutationType(
Expand Down Expand Up @@ -644,7 +641,6 @@ def test_bad_qc_dfe(self):
)


@pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows")
class DFETestMixin:
"""
Mixin for testing specific DFEs. Subclass should extend
Expand Down Expand Up @@ -694,7 +690,6 @@ def test_simulation_runs(self):
assert num_nonneutral > 0 # nonneutral mutations


@pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows")
class CatalogDFETestMixin(DFETestMixin):
"""
Mixin for DFEs in the catalog.
Expand All @@ -704,7 +699,6 @@ def test_id_valid(self):
assert utils.is_valid_dfe_id(self.dfe.id)


@pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows")
class QcdCatalogDFETestMixin(CatalogDFETestMixin):
"""
Extends the tests to also check that the qc DFE is equal to
Expand Down
4 changes: 0 additions & 4 deletions tests/test_masking.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
"""
Tests for the genetic maps management.
"""
import sys

import numpy as np
import msprime
import pytest

import stdpopsim.utils

IS_WINDOWS = sys.platform.startswith("win")


class TestMasking:
@pytest.mark.usefixtures("tmp_path")
Expand Down Expand Up @@ -119,7 +116,6 @@ def test_mask_tree_sequence(self):
assert np.all(np.logical_and(100 <= positions, positions < 200))


@pytest.mark.skipif(IS_WINDOWS, reason="SLiM not available on windows")
class TestSimulate:
@pytest.mark.filterwarnings("ignore::msprime.IncompletePopulationMetadataWarning")
def test_simulate_with_mask(self):
Expand Down
Loading

0 comments on commit 5dc0c4f

Please sign in to comment.