Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
Charles Reid | f9cc1d93f2 | 5 years ago |
Charles Reid | 09417f7c23 | 5 years ago |
Charles Reid | cf4145aee5 | 5 years ago |
Charles Reid | 98ef3fa49a | 5 years ago |
Charles Reid | 4b69492d40 | 5 years ago |
Charles Reid | c8e1760470 | 5 years ago |
Charles Reid | 861dc16a64 | 5 years ago |
Charles Reid | fc0479ff77 | 5 years ago |
Charles Reid | dae3b1dd45 | 5 years ago |
Charles Reid | 88cd2f71a6 | 5 years ago |
Charles Reid | 6c29958c13 | 5 years ago |
Charles Reid | 682f760c10 | 5 years ago |
Charles Reid | 742f24d0e5 | 5 years ago |
Charles Reid | abd4a07dec | 5 years ago |
Charles Reid | 48f4d30903 | 5 years ago |
Charles Reid | a908ddf8c2 | 5 years ago |
Charles Reid | 71f48e0f5e | 5 years ago |
17 changed files with 327 additions and 107 deletions
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
.snakemake/ |
||||
vp/ |
||||
*.egg-info/ |
||||
build/ |
||||
dist/ |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
# https://docs.travis-ci.com/user/languages/python/ |
||||
language: python |
||||
python: |
||||
- "3.5" |
||||
- "3.6" |
||||
- "3.7-dev" |
||||
# command to install dependencies |
||||
install: |
||||
- pip install -r requirements.txt |
||||
- python setup.py build install |
||||
# command to run tests |
||||
script: |
||||
- pytest |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2019 Charles Reid |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
_program = "bananas" |
||||
__version__ = "0.1.0" |
@ -0,0 +1,103 @@
@@ -0,0 +1,103 @@
|
||||
""" |
||||
Command line interface driver for snakemake workflows |
||||
""" |
||||
import argparse |
||||
import os.path |
||||
import snakemake |
||||
import sys |
||||
import pprint |
||||
import json |
||||
|
||||
from . import _program |
||||
|
||||
|
||||
thisdir = os.path.abspath(os.path.dirname(__file__)) |
||||
parentdir = os.path.join(thisdir,'..') |
||||
cwd = os.getcwd() |
||||
|
||||
def main(sysargs = sys.argv[1:]): |
||||
|
||||
parser = argparse.ArgumentParser(prog = _program, description='bananas: run snakemake workflows', usage='''bananas <workflow> <parameters> [<target>] |
||||
|
||||
bananas: run snakemake workflows, using the given workflow name & parameters file. |
||||
|
||||
''') |
||||
|
||||
parser.add_argument('workflowfile') |
||||
parser.add_argument('paramsfile') |
||||
parser.add_argument('-n', '--dry-run', action='store_true') |
||||
parser.add_argument('-f', '--force', action='store_true') |
||||
args = parser.parse_args(sysargs) |
||||
|
||||
# first, find the Snakefile |
||||
snakefile_this = os.path.join(thisdir,"Snakefile") |
||||
snakefile_parent = os.path.join(parentdir,"Snakefile") |
||||
if os.path.exists(snakefile_this): |
||||
snakefile = snakefile_this |
||||
elif os.path.exists(snakefile_parent): |
||||
snakefile = snakefile_parent |
||||
else: |
||||
msg = 'Error: cannot find Snakefile at any of the following locations:\n' |
||||
msg += '{}\n'.format(snakefile_this) |
||||
msg += '{}\n'.format(snakefile_parent) |
||||
sys.stderr.write(msg) |
||||
sys.exit(-1) |
||||
|
||||
# next, find the workflow config file |
||||
workflowfile = None |
||||
w1 = os.path.join(cwd,args.workflowfile) |
||||
w2 = os.path.join(cwd,args.workflowfile+'.json') |
||||
if os.path.exists(w1) and not os.path.isdir(w1): |
||||
workflowfile = w1 |
||||
elif os.path.exists(w2) and not os.path.isdir(w2): |
||||
workflowfile = w2 |
||||
|
||||
if not workflowfile: |
||||
msg = 'Error: cannot find workflowfile {} or {} '.format(w1,w2) |
||||
msg += 'in directory {}\n'.format(cwd) |
||||
sys.stderr.write(msg) |
||||
sys.exit(-1) |
||||
|
||||
# next, find the workflow params file |
||||
paramsfile = None |
||||
p1 = os.path.join(cwd,args.paramsfile) |
||||
p2 = os.path.join(cwd,args.paramsfile+'.json') |
||||
if os.path.exists(p1) and not os.path.isdir(p1): |
||||
paramsfile = p1 |
||||
elif os.path.exists(p2) and not os.path.isdir(p2): |
||||
paramsfile = p2 |
||||
|
||||
if not paramsfile: |
||||
msg = 'Error: cannot find paramsfile {} or {} '.format(p1,p2) |
||||
msg += 'in directory {}\n'.format(cwd) |
||||
sys.stderr.write(msg) |
||||
sys.exit(-1) |
||||
|
||||
with open(workflowfile, 'rt') as fp: |
||||
workflow_info = json.load(fp) |
||||
|
||||
target = workflow_info['workflow_target'] |
||||
config = dict() |
||||
|
||||
print('--------') |
||||
print('details!') |
||||
print('\tsnakefile: {}'.format(snakefile)) |
||||
print('\tconfig: {}'.format(workflowfile)) |
||||
print('\tparams: {}'.format(paramsfile)) |
||||
print('\ttarget: {}'.format(target)) |
||||
print('--------') |
||||
|
||||
# run bananas!! |
||||
status = snakemake.snakemake(snakefile, configfile=paramsfile, |
||||
targets=[target], printshellcmds=True, |
||||
dryrun=args.dry_run, forceall=args.force, |
||||
config=config) |
||||
|
||||
if status: # translate "success" into shell exit code of 0 |
||||
return 0 |
||||
return 1 |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
main() |
||||
|
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
appdirs==1.4.3 |
||||
certifi==2018.11.29 |
||||
chardet==3.0.4 |
||||
ConfigArgParse==0.14.0 |
||||
datrie==0.7.1 |
||||
docutils==0.14 |
||||
gitdb2==2.0.5 |
||||
GitPython==2.1.11 |
||||
idna==2.8 |
||||
jsonschema==2.6.0 |
||||
PyYAML==3.13 |
||||
ratelimiter==1.2.0.post0 |
||||
requests==2.21.0 |
||||
smmap2==2.0.5 |
||||
snakemake==5.4.0 |
||||
urllib3==1.24.1 |
||||
wrapt==1.11.0 |
@ -1,91 +0,0 @@
@@ -1,91 +0,0 @@
|
||||
#! /usr/bin/env python |
||||
""" |
||||
Execution script for snakemake workflows. |
||||
""" |
||||
import argparse |
||||
import os.path |
||||
import snakemake |
||||
import sys |
||||
import pprint |
||||
import json |
||||
|
||||
|
||||
thisdir = os.path.abspath(os.path.dirname(__file__)) |
||||
|
||||
|
||||
def main(args): |
||||
# first, find the Snakefile |
||||
snakefile = os.path.join(thisdir, 'Snakefile') |
||||
if not os.path.exists(snakefile): |
||||
sys.stderr.write('Error: cannot find Snakefile at {}\n'.format(snakefile)) |
||||
sys.exit(-1) |
||||
|
||||
# next, find the workflow config file |
||||
workflowfile = None |
||||
if os.path.exists(args.workflowfile) and not os.path.isdir(args.workflowfile): |
||||
workflowfile = args.workflowfile |
||||
else: |
||||
for suffix in ('', '.json'): |
||||
tryfile = os.path.join(thisdir, args.workflowfile + suffix) |
||||
if os.path.exists(tryfile) and not os.path.isdir(tryfile): |
||||
sys.stderr.write('Found workflowfile at {}\n'.format(tryfile)) |
||||
workflowfile = tryfile |
||||
break |
||||
|
||||
if not workflowfile: |
||||
sys.stderr.write('Error: cannot find workflowfile {}\n'.format(args.workflowfile)) |
||||
sys.exit(-1) |
||||
|
||||
# next, find the workflow params file |
||||
paramsfile = None |
||||
if os.path.exists(args.paramsfile) and not os.path.isdir(args.paramsfile): |
||||
paramsfile = args.paramsfile |
||||
else: |
||||
for suffix in ('', '.json'): |
||||
tryfile = os.path.join(thisdir, args.paramsfile + suffix) |
||||
if os.path.exists(tryfile) and not os.path.isdir(tryfile): |
||||
sys.stderr.write('Found paramsfile at {}\n'.format(tryfile)) |
||||
paramsfile = tryfile |
||||
break |
||||
|
||||
if not paramsfile: |
||||
sys.stderr.write('Error: cannot find paramsfile {}\n'.format(args.paramsfile)) |
||||
sys.exit(-1) |
||||
|
||||
with open(workflowfile, 'rt') as fp: |
||||
workflow_info = json.load(fp) |
||||
|
||||
target = workflow_info['workflow_target'] |
||||
config = dict() |
||||
|
||||
print('--------') |
||||
print('details!') |
||||
print('\tsnakefile: {}'.format(snakefile)) |
||||
print('\tconfig: {}'.format(workflowfile)) |
||||
print('\tparams: {}'.format(paramsfile)) |
||||
print('\ttarget: {}'.format(target)) |
||||
print('--------') |
||||
|
||||
# run!! |
||||
status = snakemake.snakemake(snakefile, configfile=paramsfile, |
||||
targets=[target], printshellcmds=True, |
||||
dryrun=args.dry_run, config=config) |
||||
|
||||
if status: # translate "success" into shell exit code of 0 |
||||
return 0 |
||||
return 1 |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
parser = argparse.ArgumentParser(description='run snakemake workflows', usage='''run <workflow> <parameters> [<target>] |
||||
|
||||
Run snakemake workflows, using the given workflow name & parameters file. |
||||
|
||||
''') |
||||
|
||||
parser.add_argument('workflowfile') |
||||
parser.add_argument('paramsfile') |
||||
parser.add_argument('-n', '--dry-run', action='store_true') |
||||
args = parser.parse_args() |
||||
|
||||
sys.exit(main(args)) |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
from setuptools import setup, find_packages |
||||
import glob |
||||
import os |
||||
|
||||
with open('requirements.txt') as f: |
||||
required = [x for x in f.read().splitlines() if not x.startswith("#")] |
||||
|
||||
# Note: the _program variable is set in __init__.py. |
||||
# it determines the name of the package/final command line tool. |
||||
from cli import __version__, _program |
||||
|
||||
setup(name='bananas', |
||||
version=__version__, |
||||
packages=['cli'], |
||||
test_suite='pytest.collector', |
||||
tests_require=['pytest'], |
||||
description='bananas command line interface', |
||||
url='https://charlesreid1.github.io/2019-snakemake-cli', |
||||
author='@charlesreid1', |
||||
author_email='cmreid@ucdavis.edu', |
||||
license='MIT', |
||||
entry_points=""" |
||||
[console_scripts] |
||||
{program} = cli.command:main |
||||
""".format(program = _program), |
||||
install_requires=required, |
||||
include_package_data=True, |
||||
keywords=[], |
||||
zip_safe=False) |
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
from unittest import TestCase |
||||
from subprocess import call, Popen, PIPE |
||||
import os |
||||
import shutil, tempfile |
||||
from os.path import isdir, join |
||||
|
||||
|
||||
""" |
||||
test banana |
||||
|
||||
this test will run bananas with the test |
||||
config and params provided in the test dir. |
||||
|
||||
this test will also show how to run tests where |
||||
failure is expected (i.e., checking that we handle |
||||
invalid parameters). |
||||
|
||||
each test has a unittest TestCase defined. |
||||
pytest will automatically find these tests. |
||||
""" |
||||
|
||||
|
||||
class TestBananas(TestCase): |
||||
""" |
||||
simple bananas test class |
||||
|
||||
This uses the subprocess PIPE var |
||||
to capture system input and output, |
||||
since we are running bananas from the |
||||
command line directly using subprocess. |
||||
""" |
||||
@classmethod |
||||
def setUpClass(self): |
||||
""" |
||||
set up a bananas workflow test. |
||||
|
||||
we are using the existing test/ dir |
||||
as our working dir, so no setup to do. |
||||
|
||||
if we were expecting the user to provide |
||||
a Snakefile, this is where we would set |
||||
up a test Snakefile. |
||||
""" |
||||
pass |
||||
|
||||
def test_hello(self): |
||||
""" |
||||
test hello workflow |
||||
""" |
||||
command_prefix = ['bananas','workflow-hello'] |
||||
|
||||
params = ['params-amy','params-beth'] |
||||
|
||||
pwd = os.path.abspath(os.path.dirname(__file__)) |
||||
|
||||
for param in params: |
||||
|
||||
command = command_prefix + [param] |
||||
|
||||
p = Popen(command, cwd=pwd, stdout=PIPE, stderr=PIPE).communicate() |
||||
p_out = p[0].decode('utf-8').strip() |
||||
p_err = p[1].decode('utf-8').strip() |
||||
|
||||
self.assertIn('details',p_out) |
||||
|
||||
# clean up |
||||
call(['rm','-f','hello.txt']) |
||||
|
||||
|
||||
@classmethod |
||||
def tearDownClass(self): |
||||
""" |
||||
clean up after the tests |
||||
""" |
||||
pass |
||||
|
Loading…
Reference in new issue