diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..68bc2342 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,43 @@ +amply==0.1.4 +appdirs==1.4.4 +attrs==20.3.0 +bids-validator==1.5.8 +certifi==2020.12.5 +chardet==3.0.4 +click==7.1.2 +ConfigArgParse==1.2.3 +datrie==0.8.2 +docopt==0.6.2 +docutils==0.16 +gitdb==4.0.5 +GitPython==3.1.11 +idna==2.10 +ipython-genutils==0.2.0 +jsonschema==3.2.0 +jupyter-core==4.7.0 +nbformat==5.0.8 +nibabel==3.2.1 +num2words==0.5.10 +numpy==1.19.4 +packaging==20.8 +pandas==1.1.5 +patsy==0.5.1 +psutil==5.7.3 +PuLP==2.3.1 +pybids==0.12.3 +pyparsing==2.4.7 +pyrsistent==0.17.3 +python-dateutil==2.8.1 +pytz==2020.4 +PyYAML==5.3.1 +ratelimiter==1.2.0.post0 +requests==2.25.0 +scipy==1.5.4 +six==1.15.0 +smmap==3.0.4 +snakemake==5.30.1 +SQLAlchemy==1.3.20 +toposort==1.5 +traitlets==5.0.5 +urllib3==1.26.2 +wrapt==1.12.1 diff --git a/setup.py b/setup.py index 342973ff..472bcb2e 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="snakebids", - version="0.1.5", + version="0.2.0", author="Ali Khan", author_email="alik@robarts.ca", description="BIDS integration into snakemake workflows", diff --git a/snakebids/app.py b/snakebids/app.py index 777aaa2e..c197cfbd 100644 --- a/snakebids/app.py +++ b/snakebids/app.py @@ -57,7 +57,7 @@ def run(command, env={}): class SnakeBidsApp: - def __init__(self, snakemake_dir): + def __init__(self, snakemake_dir, skip_parse_args=False): #input argument is the dir where snakemake would be run # we use this to locate the config file, and snakefile adding them to generated_config @@ -95,27 +95,32 @@ def __init__(self, snakemake_dir): - - self.parse_args() + self.__load_config() #add path to snakefile to the config -- so workflows can grab files relative to the snakefile folder self.config['snakemake_dir'] = snakemake_dir - self.write_updated_config() + self.parser = self.__create_parser() + if not skip_parse_args: + self.__parse_args() - - def parse_args(self): - - #replace with proper name of pipeline here - parser = argparse.ArgumentParser(description='snakebids-app') + def __load_config(self): #load up workflow config file with open(self.snakebids_config, 'r') as infile: self.config = yaml.load(infile, Loader=yaml.FullLoader) + + + + def __create_parser(self): + + #replace with proper name of pipeline here + parser = argparse.ArgumentParser(description='snakebids-app') + #update the parser with config options for name, parse_args in self.config['parse_args'].items(): parser.add_argument(name, **parse_args) @@ -133,14 +138,17 @@ def parse_args(self): help=f'Filters (PyBIDS) for {input_type}, where {arginstance} is ' f'key=value pair(s) (default: {arglist_default_string})') + return parser + + + def __parse_args(self): + - all_args = parser.parse_known_args() + all_args = self.parser.parse_known_args() args = all_args[0] snakemake_args = all_args[1] - - #add arguments to config self.config.update(args.__dict__) @@ -160,7 +168,8 @@ def parse_args(self): self.config['output_dir'] = os.path.realpath(self.config['output_dir']) - def write_updated_config(self): + + def __write_updated_config(self): #create an updated snakebids config file self.updated_config = os.path.join(self.config['output_dir'],'config','snakebids.yml') @@ -176,6 +185,9 @@ def write_updated_config(self): #workflow snakefile will read snakebids config, create inputs_config, read that in def run_snakemake(self): + #write updated config + self.__write_updated_config() + # running the chosen participant level analysis_level = self.config['analysis_level'] diff --git a/snakebids/tests/__init__.py b/snakebids/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/snakebids/tests/test_bids.py b/snakebids/tests/test_bids.py new file mode 100644 index 00000000..5c81f4a7 --- /dev/null +++ b/snakebids/tests/test_bids.py @@ -0,0 +1,6 @@ +from .. import bids + +def test_bids_subj(): + assert bids(root='bids',subject='001',suffix='T1w.nii.gz') == 'bids/sub-001/sub-001_T1w.nii.gz' + + diff --git a/template_app/README.md b/template_app/README.md deleted file mode 100644 index 3356dc61..00000000 --- a/template_app/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# example app - -This is an example README for a snakebids app diff --git a/template_app/README.rst b/template_app/README.rst new file mode 100644 index 00000000..7da83935 --- /dev/null +++ b/template_app/README.rst @@ -0,0 +1,4 @@ +Template App +============ + +Description of app goes here diff --git a/template_app/config/snakebids.yml b/template_app/app_name/config/snakebids.yml similarity index 100% rename from template_app/config/snakebids.yml rename to template_app/app_name/config/snakebids.yml diff --git a/template_app/pipeline_description.json b/template_app/app_name/pipeline_description.json similarity index 54% rename from template_app/pipeline_description.json rename to template_app/app_name/pipeline_description.json index ecc54605..c664abd0 100644 --- a/template_app/pipeline_description.json +++ b/template_app/app_name/pipeline_description.json @@ -4,9 +4,12 @@ "DatasetType": "derivative", "GeneratedBy": [ { - "Name": "appname", + "Name": "app_name", "Version": "0.1.0", - "CodeURL": "http://github.com/org/name" + "CodeURL": "http://github.com/org/name", + "Author": "Author name here", + "AuthorEmail": "Author email" + } ] } diff --git a/template_app/run.py b/template_app/app_name/run.py similarity index 55% rename from template_app/run.py rename to template_app/app_name/run.py index 8dc200e5..9da492ae 100755 --- a/template_app/run.py +++ b/template_app/app_name/run.py @@ -3,8 +3,13 @@ from snakebids.app import SnakeBidsApp -def main(): +def get_parser(): + """Exposes parser for sphinx doc generation, cwd is the docs dir""" + app = SnakeBidsApp('../app_name',skip_parse_args=True) + return app.parser + +def main(): app = SnakeBidsApp(os.path.abspath(os.path.dirname(__file__))) app.run_snakemake() diff --git a/template_app/workflow/Snakefile b/template_app/app_name/workflow/Snakefile similarity index 100% rename from template_app/workflow/Snakefile rename to template_app/app_name/workflow/Snakefile diff --git a/template_app/docs/.gitignore b/template_app/docs/.gitignore new file mode 100644 index 00000000..e35d8850 --- /dev/null +++ b/template_app/docs/.gitignore @@ -0,0 +1 @@ +_build diff --git a/template_app/docs/Makefile b/template_app/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/template_app/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/template_app/docs/conf.py b/template_app/docs/conf.py new file mode 100644 index 00000000..06ef387f --- /dev/null +++ b/template_app/docs/conf.py @@ -0,0 +1,63 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) +import sphinx_rtd_theme + + +# -- Project information ----------------------------------------------------- + + +project = 'app_name' +copyright = '2020, Authors here' +author = 'Authors here' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx_rtd_theme", + "sphinxarg.ext", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +master_doc = 'index' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "sphinx_rtd_theme" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + + + + diff --git a/template_app/docs/getting_started/installation.rst b/template_app/docs/getting_started/installation.rst new file mode 100644 index 00000000..5cda2998 --- /dev/null +++ b/template_app/docs/getting_started/installation.rst @@ -0,0 +1,56 @@ +Installation +============ + +Template snakebids BIDS App + + +Requirements +------------ + +Docker (Mac/Windows/Linux) or Singularity (Linux) + +Docker: +^^^^^^^ + +Pull the container: + +.. code-block:: + + docker pull khanlab/app_name:latest + +do a dry run, printing the command at each step: + +.. code-block:: + + docker run -it --rm -v PATH_TO_BIDS_DIR:/bids:ro -v PATH_TO_OUTPUT_DIR:/output khanlab/app_name:latest /bids /output participant -np + +run it with maximum number of cores: + +.. code-block:: + + docker run -it --rm -v PATH_TO_BIDS_DIR:/bids:ro -v PATH_TO_OUTPUT_DIR:/output khanlab/app_name:latest /bids /output participant -p --cores all + + +Singularity: +^^^^^^^^^^^^ + +Pull the container: + +.. code-block:: + + singularity pull khanlab_app_name_latest.sif docker://khanlab/app_name:latest + +do a dry run, printing the command at each step: + +.. code-block:: + + singularity run -e khanlab_app_name_latest.sif khanlab/app_name:latest PATH_TO_BIDS_DIR PATH_TO_OUTPUT_DIR participant -np + +run it with maximum number of cores: + +.. code-block:: + + singularity run -e khanlab_app_name_latest.sif khanlab/app_name:latest PATH_TO_BIDS_DIR PATH_TO_OUTPUT_DIR participant -p --cores all + + + diff --git a/template_app/docs/index.rst b/template_app/docs/index.rst new file mode 100644 index 00000000..4377f087 --- /dev/null +++ b/template_app/docs/index.rst @@ -0,0 +1,32 @@ +.. hippunfold documentation master file, created by + sphinx-quickstart on Thu Jul 30 10:15:34 2020. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +.. include:: ../README.rst + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + +.. toctree:: + :caption: Getting started + :name: getting_started + :hidden: + :maxdepth: 1 + + getting_started/installation + +.. toctree:: + :caption: Usage + :name: usage + :hidden: + :maxdepth: 1 + + usage/app_cli + usage/snakemake_cli + + + + diff --git a/template_app/docs/requirements.txt b/template_app/docs/requirements.txt new file mode 100644 index 00000000..17115ac9 --- /dev/null +++ b/template_app/docs/requirements.txt @@ -0,0 +1,3 @@ +sphinx-argparse +sphinx_rtd_theme +snakebids==0.2.0 diff --git a/template_app/docs/usage/app_cli.rst b/template_app/docs/usage/app_cli.rst new file mode 100644 index 00000000..31ba495e --- /dev/null +++ b/template_app/docs/usage/app_cli.rst @@ -0,0 +1,9 @@ +Command line interface +-------------------- + +.. argparse:: + :filename: ../app_name/run.py + :func: get_parser + :prog: hippunfold + + diff --git a/template_app/docs/usage/snakemake_cli.rst b/template_app/docs/usage/snakemake_cli.rst new file mode 100644 index 00000000..f8261fbc --- /dev/null +++ b/template_app/docs/usage/snakemake_cli.rst @@ -0,0 +1,9 @@ +Snakemake Command line interface +________________________________ + +.. argparse:: + :module: snakemake + :func: get_argument_parser + :prog: snakemake + + diff --git a/template_app/setup.py b/template_app/setup.py index a4441923..834a395d 100644 --- a/template_app/setup.py +++ b/template_app/setup.py @@ -1,37 +1,40 @@ -import json import setuptools +import json -with open("README.md", "r") as fh: +with open("README.rst", "r") as fh: long_description = fh.read() -with open('pipeline_description.json', 'r') as fh: +with open('app_name/pipeline_description.json', 'r') as fh: pipeline = json.load(fh) - print(pipeline) name = pipeline['GeneratedBy'][0]['Name'] description = pipeline['Name'] version = pipeline['GeneratedBy'][0]['Version'] url = pipeline['GeneratedBy'][0]['CodeURL'] - - + author = pipeline['GeneratedBy'][0]['Author'] + author_email = pipeline['GeneratedBy'][0]['AuthorEmail'] + setuptools.setup( name=name, version=version, - author="Ali Khan", - author_email="alik@robarts.ca", + author=author, + author_email=author_email, description=description, long_description=long_description, - long_description_content_type="text/markdown", + long_description_content_type="text/x-rst", url=url, packages=setuptools.find_packages(), + include_package_data=True, classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ], + entry_points={'console_scripts': [ + 'hippunfold=hippunfold.run:main' + ]}, install_requires=[ - "pybids==0.12.3", - "snakemake==5.28.0", - "PyYAML==5.3.1", + "snakebids>=0.2.0", + "snakemake>=5.28.0" ], python_requires='>=3.7' )