From 46c0cc357737ca7033eac7f5d6ca6b03a395ec1c Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 2 Jan 2017 21:40:01 -0500 Subject: [PATCH 1/2] move tmpdir_for_func to utils module --- test/conftest.py | 7 +------ test/utils.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 8bca5f3..c4c2a48 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -6,17 +6,12 @@ from snakemake.shell import shell from snakemake.utils import makedirs from lcdblib.snakemake import aligners -from utils import run, dpath, symlink_in_tempdir +from utils import run, dpath, symlink_in_tempdir, tmpdir_for_func # test data url URL = 'https://github.com/lcdb/lcdb-test-data/blob/master/data/{}?raw=true' -def tmpdir_for_func(factory): - caller = inspect.stack()[1][3] - return str(factory.mktemp(caller)) - - def _download_file(fn, d): """ Intended to be called from a pytest.fixture function below. diff --git a/test/utils.py b/test/utils.py index 5934e08..251bd7e 100644 --- a/test/utils.py +++ b/test/utils.py @@ -11,15 +11,26 @@ import urllib import shutil import shlex +import inspect import pytest from snakemake import snakemake from snakemake.shell import shell - SCRIPTPATH = shutil.which('snakemake') + +def tmpdir_for_func(factory): + """ + Returns a tempdir named after the calling function. + + `factory` is a pytest.tmpdir_factory instance. + """ + caller = inspect.stack()[1][3] + return str(factory.mktemp(caller)) + + def dpath(path): "path relative to this file" return os.path.realpath(os.path.join(os.path.dirname(__file__), path)) From 79fcc43cd72c9e78d216876d54e11cee91ee8eb8 Mon Sep 17 00:00:00 2001 From: Ryan Dale Date: Mon, 2 Jan 2017 21:46:05 -0500 Subject: [PATCH 2/2] add test_toy.py --- test/test_toy.py | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 test/test_toy.py diff --git a/test/test_toy.py b/test/test_toy.py new file mode 100644 index 0000000..a8e63a1 --- /dev/null +++ b/test/test_toy.py @@ -0,0 +1,100 @@ +import os +from textwrap import dedent +import pytest +import utils + +# Each module has a config dict +config = dict() + + +def generic_fixture(key, mapping, factory): + """ + Tries to handle as much of the magic as possible. + + Parameters + ---------- + key : str + Key into the module-level config dict + + mapping : dict + Maps paths from fixtures to input files expected by the snakefile + + tmpdir : str + Path to temporary dir, usually created by utils.tmpdir_for_func + + Returns + ------- + After a successful Snakemake run, returns the dictionary of the config's + `output` key but with paths fixed to be relative to tmpdir. This returned + dict is ready to be used as a fixture by test functions. + """ + conf = config[key] + tmpdir = utils.tmpdir_for_func(factory) + input_data_func = utils.symlink_in_tempdir(mapping) + utils.run(utils.dpath(conf['wrapper']), conf['snakefile'], None, input_data_func, tmpdir) + output = conf['output'].copy() + for k, v in output.items(): + output[k] = os.path.join(tmpdir, v) + return output + + +# In order for the doc generation to find this config info without re-running +# all tests, it needs to be in the module-level dict. It similarly can't be +# added during the fixture function's runtime. +# +# However, the mapping and tmpdir must be provided by the function, so the +# config and the function are tightly coupled. +# +# So we add the item to the dictionary here, right above the function that will +# be using it to keep them tightly coupled in the file. +config['hisat2_index'] = dict( + description="Basic example of generating a hisat2 index", + wrapper="../wrappers/hisat2/build", + snakefile=""" + rule hisat2_build: + input: + fasta="2L.fa" + output: + index=expand("hisat2_index/assembly.{n}.ht2", n=range(1,9)) + log: "hisat.log" + wrapper: "file://wrapper" + """, + output={'prefix': 'hisat2_index/assembly'} +) + + +# All the hard work is done in the config and in generic_fixture(). Now we just +# need to set up the correct mapping of fixtures to input files. +@pytest.fixture(scope='module') +def hisat2_index(tmpdir_factory, dm6_fa): + mapping = {dm6_fa: '2L.fa'} + return generic_fixture('hisat2_index', mapping, tmpdir_factory) + +# The actual test. +def test_index(hisat2_index): + assert os.path.exists(hisat2_index['prefix'] + '.1.ht2') + + +def extract_examples_for_wrapper(wrapper): + """ + Returns the examples for the wrapper in markdown format. + + Parameters + ---------- + wrapper : str + Expected to be the value of one of the config dict's `wrapper` keys. + """ + markdown = [] + for k, v in config.items(): + if v['wrapper'] != wrapper: + continue + snakefile = dedent(v['snakefile']) + markdown.append( + dedent( + """ + {} + + ```python""".format(v['description']))) + markdown.append(snakefile) + markdown.append("```") + return "\n".join(markdown)