diff --git a/.github/workflows/test-spras.yml b/.github/workflows/test-spras.yml index ea338ad37..fbc900c33 100644 --- a/.github/workflows/test-spras.yml +++ b/.github/workflows/test-spras.yml @@ -50,8 +50,12 @@ jobs: # Install spras in the environment using pip shell: bash --login {0} run: pip install . - - name: Log conda environment - # Log conda environment contents + - name: Get pipx + shell: bash --login {0} + run: pip install pipx + - shell: bash --login {0} + run: pipx install . + - name: Log conda environment contents shell: bash --login {0} run: conda list - name: Install Apptainer @@ -91,7 +95,7 @@ jobs: # We enable high parallelization (cores 4) to test our way out of the experienced # race conditions from #268 and #279 # We also enforce strict DAG evaluation to catch DAG problems before they appear as user errors. (#359) - run: snakemake --cores 4 --configfile config/config.yaml --show-failed-logs --strict-dag-evaluation cyclic-graph --strict-dag-evaluation functions --strict-dag-evaluation periodic-wildcards + run: spras run --cores 4 --configfile config/config.yaml --show-failed-logs --strict-dag-evaluation cyclic-graph --strict-dag-evaluation functions --strict-dag-evaluation periodic-wildcards # Run pre-commit checks on source files pre-commit: diff --git a/MANIFEST.in b/MANIFEST.in index 72dcf4891..0afcd18fa 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,4 @@ +include README.md +include LICENSE +include Snakefile include spras/cgroup_wrapper.sh diff --git a/README.md b/README.md index 44895c76b..21966070e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ After installing Docker, start Docker before running SPRAS. Once you have activated the conda environment and started Docker, you can run SPRAS with the example Snakemake workflow. From the root directory of the `spras` repository, run the command ``` -snakemake --cores 1 --configfile config/config.yaml +spras run --cores 1 --configfile config/config.yaml ``` This will run the SPRAS workflow with the example config file (`config/config.yaml`) and input files. Output files will be written to the `output` directory. diff --git a/docs/contributing/index.rst b/docs/contributing/index.rst index 600d05a02..2f002a6de 100644 --- a/docs/contributing/index.rst +++ b/docs/contributing/index.rst @@ -296,7 +296,7 @@ through SPRAS with .. code:: bash - snakemake --cores 1 --configfile config/config.yaml + spras run --cores 1 --configfile config/config.yaml Make sure to run the command inside the ``spras`` conda environment. diff --git a/docs/usage.rst b/docs/usage.rst index 33460d858..2537f67b7 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -2,14 +2,14 @@ Using SPRAS =========== SPRAS is run through `Snakemake `_, which comes -with the SPRAS conda environment. +with both the SPRAS conda environment and as a dependency of SPRAS. To run SPRAS, run the following command inside the ``spras`` directory, specifying a ``config.yaml`` and the number of cores to run SPRAS with: .. code-block:: bash - snakemake --cores 1 --configfile config.yaml + spras run --cores 1 --configfile config.yaml Parallelizing SPRAS ------------------- @@ -23,7 +23,7 @@ To parallelize SPRAS, specify ``--cores`` to be a value higher than ``1``: .. code-block:: bash - snakemake --cores 4 --configfile config.yaml + spras run --cores 4 --configfile config.yaml SPRAS also supports high-performance computing with it's integration with `HTCondor `_. See :doc:`Running with HTCondor <../htcondor>` diff --git a/pyproject.toml b/pyproject.toml index 424f183cf..d215eee3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,12 @@ dev = [ "Homepage" = "https://github.com/Reed-CompBio/spras" "Issues" = "https://github.com/Reed-CompBio/spras/issues" +[project.entry-points."pipx.run"] +spras = "spras.cli:run" + +[project.scripts] +spras = "spras.cli:run" + [build-system] requires = ["setuptools>=64.0"] build-backend = "setuptools.build_meta" diff --git a/spras/__main__.py b/spras/__main__.py new file mode 100644 index 000000000..16b442b7e --- /dev/null +++ b/spras/__main__.py @@ -0,0 +1,3 @@ +if __name__ == "__main__": + from spras.cli import run + run() diff --git a/spras/cli.py b/spras/cli.py new file mode 100644 index 000000000..eaef47492 --- /dev/null +++ b/spras/cli.py @@ -0,0 +1,53 @@ +import argparse +import itertools +import os +import subprocess +from pathlib import Path + +# https://stackoverflow.com/a/5137509/7589775 +# The file we want, Snakefile, is also included in MANIFEST.in +dir_path = os.path.dirname(os.path.realpath(__file__)) +# we resolve to simplify the path name in errors +snakefile_path = Path(dir_path, "..", "Snakefile").resolve() + +# Removes the very awkwardly phrased "{subcommand1, subcommand2}" from the subcommand help +# from https://stackoverflow.com/a/13429281/7589775 +class SubcommandHelpFormatter(argparse.RawDescriptionHelpFormatter): + def _format_action(self, action): + parts = super(argparse.RawDescriptionHelpFormatter, self)._format_action(action) + if action.nargs == argparse.PARSER: + parts = "\n".join(parts.split("\n")[1:]) + return parts + +def get_parser(): + parser = argparse.ArgumentParser( + prog='SPRAS', + description='The wrapping tool for SPRAS (signaling pathway reconstruction analysis streamliner)', + epilog='SPRAS is in alpha. Report issues or suggest features on GitHub: https://github.com/Reed-CompBio/spras', + formatter_class=SubcommandHelpFormatter) + + subparsers = parser.add_subparsers(title='subcommands', + help='subcommand help', + dest='subcommand') + subparsers = subparsers.add_parser('run', + help='Run the SPRAS Snakemake workflow', + # We let snakemake handle help + add_help=False) + + return parser + +def run(): + parser = get_parser() + (args, unknown_args) = parser.parse_known_args() + + if args.subcommand == "run": + subprocess.run(list(itertools.chain( + ["snakemake", "-s", snakefile_path], + unknown_args + ))) + return + + parser.print_help() + +if __name__ == '__main__': + run()