diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ecefd7a5..ef26a63f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -169,7 +169,7 @@ After completing this step, try running the Local Neighborhood algorithm through ```bash snakemake --cores 1 --configfile config/config.yaml ``` -Make sure to run the command inside the `spras` conda environment. +Make sure to run the command inside the `spras` conda environment. If installing via `pip` instead of using conda, install with the `-e .[dev]` options (the full command to run from the repo root is `python -m pip install -e .[dev]`) so that Python picks up any changes you make and installs all optional development packages. Omitting the `-e` flag will prevent your changes from being reflected unless you force re-install, and omitting `.[dev]` will prevent pip from installing `pre-commit` and `pytest`. As a workflow manager, Snakemake will consider the work described in the configuration file to be completed once the necessary output files have been written to the relevant output directory (`output` in the `config/config.yaml` configuration). That means that if you change your code and rerun the Snakemake command above, nothing may happen if the output files already exist. @@ -223,7 +223,7 @@ Example errors include a yaml file that cannot be parsed or a local variable tha These tests are run automatically on every commit through the GitHub Actions. However, developers will benefit from setting up their environment to run the same tests locally while they modify the SPRAS source. -The `pre-commit` package is installed as part of the conda environment in `environment.yml`. +The `pre-commit` package is installed as part of the conda environment in `environment.yml`, or when installing SPRAS with `python -m pip install -e .[dev]`. From there, the pre-commit [quick start](https://pre-commit.com/#quick-start) guide explains two primary ways to use it locally: - run against all source files with `pre-commit run --all-files` to identify errors and automatically fix them when possible - configure `git` to run the hooks before every `git commit` so that a commit will only succeed if the tests pass, ensuring new errors are not introduced diff --git a/README.md b/README.md index 9a2593a9..8dc81a2b 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,13 @@ conda activate spras to create a conda environment with the required packages and activate that environment. If you have a different version of Python already, you can install the specified versions of the required packages in your preferred manner instead of using Anaconda. +SPRAS can also be installed with Python's package manager `pip` by running `python -m pip install .` from the repo's root directory. This makes SPRAS more portable by allowing you to run +snakemake anywhere the Snakefile, data, and configuration file can be accessed. However, use caution when pip installing directly to your computer without using some form of virtual +environment as this can alter your system's underlying python modules, which could lead to unexpected behavior. + +For developers, SPRAS can be installed via `pip` with the `-e` flag, as in `python -m pip install -e .`. This points Python back to the SPRAS repo so that any changes made to the source +code are reflected in the installed module. + You also need to install [Docker](https://docs.docker.com/get-docker/). After installing Docker, start Docker before running SPRAS. @@ -60,7 +67,7 @@ The files to create these Docker images are in the `docker-wrappers` subdirector The Docker images are available on [DockerHub](https://hub.docker.com/orgs/reedcompbio). **Python wrapper for calling algorithms**: Wrapper functions provide an interface between the common file formats for input and output data and the algorithm-specific file formats and reconstruction commands. -These wrappers are in the `src/` subdirectory. +These wrappers are in the `spras/` subdirectory. **Test code**: Tests for the Docker wrappers and SPRAS code. The tests require the conda environment in `environment.yml` and Docker. diff --git a/Snakefile b/Snakefile index 836e67e8..994dc03e 100644 --- a/Snakefile +++ b/Snakefile @@ -1,10 +1,10 @@ import os -from src import runner +from spras import runner import shutil import yaml -from src.dataset import Dataset -from src.util import process_config -from src.analysis import ml, summary, graphspace, cytoscape +from spras.dataset import Dataset +from spras.util import process_config +from spras.analysis import ml, summary, graphspace, cytoscape # Snakemake updated the behavior in the 6.5.0 release https://github.com/snakemake/snakemake/pull/1037 # and using the wrong separator prevents Snakemake from matching filenames to the rules that can produce them diff --git a/environment.yml b/environment.yml index 3d3fb949..75546ef0 100644 --- a/environment.yml +++ b/environment.yml @@ -13,7 +13,7 @@ dependencies: - python=3.8 - pip=22.1 - requests=2.28 - - scikit-learn=1.1 + - scikit-learn=1.2 - seaborn=0.12 - spython=0.2 # Only required for GraphSpace @@ -25,4 +25,4 @@ dependencies: - sphinx=5.0 - pip: - graphspace_python==1.3.1 - - sphinx-rtd-theme==1.0.0 + - sphinx-rtd-theme==1.2.0 diff --git a/pyproject.toml b/pyproject.toml index f9ca5516..5962fc3c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,60 @@ +[project] +name = "spras" +version = "0.0.1" +description = "Signaling Pathway Reconstruction Analysis Streamliner" +authors = [ + { name = "Anthony Gitter", email = "gitter@biostat.wisc.edu" }, + { name = "Anna Ritz", email = "aritz@reed.edu"}, +] +license = { file = "LICENSE" } +readme = "README.md" +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Topic :: Scientific/Engineering :: Bio-Informatics", +] +requires-python = ">=3.8" +dependencies = [ + "adjusttext==0.7.3", + "snakemake==7.19.1", + "docker==5.0.3", # Switched from docker-py to docker because docker-py is not maintained in pypi. This appears to have no effect + "matplotlib==3.5", + "networkx==2.8", + "pandas==1.4", + "pip==22.1", + "requests==2.28", + "scikit-learn==1.2", + "seaborn==0.12", + "spython==0.2", + # Only required for GraphSpace + "commonmark==0.9", + "docutils==0.18", + "jinja2==3.1", + "mock==4.0", + "recommonmark==0.7", + "sphinx==5.0", + "graphspace_python==1.3.1", + "sphinx-rtd-theme==1.2.0", +] + +[project.optional-dependencies] +dev = [ + # Only required for development + "pre-commit==2.20", + "pytest==7.1", +] + +[project.urls] +"Homepage" = "https://github.com/Reed-CompBio/spras" +"Issues" = "https://github.com/Reed-CompBio/spras/issues" + +[build-system] +requires = ["setuptools>=64.0"] +build-backend = "setuptools.build_meta" + [tool.ruff] target-version = "py38" # Autofix errors when possible @@ -16,3 +73,9 @@ select = [ "I", # isort "W292", # missing-newline-at-end-of-file ] + +[tool.setuptools] +# py-modules tells setuptools which directory is our actual module +py-modules = ["spras"] +# packages tells setuptools what the exported package is called (ie allows import spras) +packages = ["spras", "spras.analysis"] diff --git a/src/__init__.py b/spras/__init__.py similarity index 100% rename from src/__init__.py rename to spras/__init__.py diff --git a/src/allpairs.py b/spras/allpairs.py similarity index 98% rename from src/allpairs.py rename to spras/allpairs.py index 10808415..f7fdf70f 100644 --- a/src/allpairs.py +++ b/spras/allpairs.py @@ -3,8 +3,8 @@ import pandas as pd -from src.prm import PRM -from src.util import prepare_volume, run_container +from spras.prm import PRM +from spras.util import prepare_volume, run_container __all__ = ['AllPairs'] diff --git a/src/analysis/__init__.py b/spras/analysis/__init__.py similarity index 100% rename from src/analysis/__init__.py rename to spras/analysis/__init__.py diff --git a/src/analysis/cytoscape.py b/spras/analysis/cytoscape.py similarity index 98% rename from src/analysis/cytoscape.py rename to spras/analysis/cytoscape.py index df533784..66247566 100644 --- a/src/analysis/cytoscape.py +++ b/spras/analysis/cytoscape.py @@ -2,7 +2,7 @@ from shutil import rmtree from typing import List, Union -from src.util import prepare_volume, run_container +from spras.util import prepare_volume, run_container def run_cytoscape(pathways: List[Union[str, PurePath]], output_file: str, singularity: bool = False) -> None: diff --git a/src/analysis/graphspace.py b/spras/analysis/graphspace.py similarity index 100% rename from src/analysis/graphspace.py rename to spras/analysis/graphspace.py diff --git a/src/analysis/ml.py b/spras/analysis/ml.py similarity index 99% rename from src/analysis/ml.py rename to spras/analysis/ml.py index 2a2508c2..44bbec6b 100644 --- a/src/analysis/ml.py +++ b/spras/analysis/ml.py @@ -12,7 +12,7 @@ from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler -from src.util import make_required_dirs +from spras.util import make_required_dirs plt.switch_backend('Agg') diff --git a/src/analysis/summary.py b/spras/analysis/summary.py similarity index 100% rename from src/analysis/summary.py rename to spras/analysis/summary.py diff --git a/src/dataset.py b/spras/dataset.py similarity index 100% rename from src/dataset.py rename to spras/dataset.py diff --git a/src/domino.py b/spras/domino.py similarity index 99% rename from src/domino.py rename to spras/domino.py index cbfb1f12..c11725f3 100644 --- a/src/domino.py +++ b/spras/domino.py @@ -3,8 +3,8 @@ import pandas as pd -from src.prm import PRM -from src.util import prepare_volume, run_container +from spras.prm import PRM +from spras.util import prepare_volume, run_container __all__ = ['DOMINO', 'pre_domino_id_transform', 'post_domino_id_transform'] diff --git a/src/meo.py b/spras/meo.py similarity index 99% rename from src/meo.py rename to spras/meo.py index 3890a83c..45100963 100644 --- a/src/meo.py +++ b/spras/meo.py @@ -2,8 +2,8 @@ import pandas as pd -from src.prm import PRM -from src.util import prepare_volume, run_container +from spras.prm import PRM +from spras.util import prepare_volume, run_container __all__ = ['MEO', 'write_properties'] diff --git a/src/mincostflow.py b/spras/mincostflow.py similarity index 98% rename from src/mincostflow.py rename to spras/mincostflow.py index fc6deaba..c4bd06f7 100644 --- a/src/mincostflow.py +++ b/spras/mincostflow.py @@ -2,8 +2,8 @@ import pandas as pd -from src.prm import PRM -from src.util import prepare_volume, run_container +from spras.prm import PRM +from spras.util import prepare_volume, run_container __all__ = ['MinCostFlow'] diff --git a/src/omicsintegrator1.py b/spras/omicsintegrator1.py similarity index 99% rename from src/omicsintegrator1.py rename to spras/omicsintegrator1.py index 3b667863..5c07fc13 100644 --- a/src/omicsintegrator1.py +++ b/spras/omicsintegrator1.py @@ -2,8 +2,8 @@ import pandas as pd -from src.prm import PRM -from src.util import prepare_volume, run_container +from spras.prm import PRM +from spras.util import prepare_volume, run_container __all__ = ['OmicsIntegrator1', 'write_conf'] diff --git a/src/omicsintegrator2.py b/spras/omicsintegrator2.py similarity index 98% rename from src/omicsintegrator2.py rename to spras/omicsintegrator2.py index 0147dd49..e0f5dca7 100644 --- a/src/omicsintegrator2.py +++ b/spras/omicsintegrator2.py @@ -2,9 +2,9 @@ import pandas as pd -from src.dataset import Dataset -from src.prm import PRM -from src.util import add_rank_column, prepare_volume, run_container +from spras.dataset import Dataset +from spras.prm import PRM +from spras.util import add_rank_column, prepare_volume, run_container __all__ = ['OmicsIntegrator2'] diff --git a/src/pathlinker.py b/spras/pathlinker.py similarity index 98% rename from src/pathlinker.py rename to spras/pathlinker.py index 27f4d294..ccd630ec 100644 --- a/src/pathlinker.py +++ b/spras/pathlinker.py @@ -3,8 +3,8 @@ import pandas as pd -from src.prm import PRM -from src.util import prepare_volume, run_container +from spras.prm import PRM +from spras.util import prepare_volume, run_container __all__ = ['PathLinker'] diff --git a/src/prm.py b/spras/prm.py similarity index 100% rename from src/prm.py rename to spras/prm.py diff --git a/src/runner.py b/spras/runner.py similarity index 84% rename from src/runner.py rename to spras/runner.py index 64a5aa88..6ef26496 100644 --- a/src/runner.py +++ b/spras/runner.py @@ -1,12 +1,12 @@ # supported algorithm imports -from src.allpairs import AllPairs as allpairs -from src.dataset import Dataset -from src.domino import DOMINO as domino -from src.meo import MEO as meo -from src.mincostflow import MinCostFlow as mincostflow -from src.omicsintegrator1 import OmicsIntegrator1 as omicsintegrator1 -from src.omicsintegrator2 import OmicsIntegrator2 as omicsintegrator2 -from src.pathlinker import PathLinker as pathlinker +from spras.allpairs import AllPairs as allpairs +from spras.dataset import Dataset +from spras.domino import DOMINO as domino +from spras.meo import MEO as meo +from spras.mincostflow import MinCostFlow as mincostflow +from spras.omicsintegrator1 import OmicsIntegrator1 as omicsintegrator1 +from spras.omicsintegrator2 import OmicsIntegrator2 as omicsintegrator2 +from spras.pathlinker import PathLinker as pathlinker def run(algorithm, params): diff --git a/src/util.py b/spras/util.py similarity index 100% rename from src/util.py rename to spras/util.py diff --git a/test/AllPairs/test_ap.py b/test/AllPairs/test_ap.py index f1c82f85..b5874a9c 100644 --- a/test/AllPairs/test_ap.py +++ b/test/AllPairs/test_ap.py @@ -4,7 +4,7 @@ import pytest -from src.allpairs import AllPairs +from spras.allpairs import AllPairs TEST_DIR = 'test/AllPairs/' OUT_DIR = TEST_DIR+'output/' diff --git a/test/DOMINO/test_domino.py b/test/DOMINO/test_domino.py index a4d69339..2a5b33ba 100644 --- a/test/DOMINO/test_domino.py +++ b/test/DOMINO/test_domino.py @@ -4,7 +4,7 @@ import pytest -from src.domino import DOMINO, post_domino_id_transform, pre_domino_id_transform +from spras.domino import DOMINO, post_domino_id_transform, pre_domino_id_transform TEST_DIR = 'test/DOMINO/' OUT_FILE_DEFAULT = TEST_DIR+'output/domino-output.txt' diff --git a/test/MEO/test_meo.py b/test/MEO/test_meo.py index 11c2766e..724e4ae5 100644 --- a/test/MEO/test_meo.py +++ b/test/MEO/test_meo.py @@ -3,7 +3,7 @@ import pytest -from src.meo import MEO, write_properties +from spras.meo import MEO, write_properties TEST_DIR = 'test/MEO/' OUT_FILE = TEST_DIR + 'output/edges.txt' diff --git a/test/MinCostFlow/test_mcf.py b/test/MinCostFlow/test_mcf.py index 1e832ad9..2a404387 100644 --- a/test/MinCostFlow/test_mcf.py +++ b/test/MinCostFlow/test_mcf.py @@ -3,7 +3,7 @@ import pytest -from src.mincostflow import MinCostFlow +from spras.mincostflow import MinCostFlow TEST_DIR = 'test/MinCostFlow/' OUT_FILE = TEST_DIR + 'output/mincostflow-output.txt' diff --git a/test/OmicsIntegrator1/test_oi1.py b/test/OmicsIntegrator1/test_oi1.py index b0b88355..c361b309 100644 --- a/test/OmicsIntegrator1/test_oi1.py +++ b/test/OmicsIntegrator1/test_oi1.py @@ -3,7 +3,7 @@ import pytest -from src.omicsintegrator1 import OmicsIntegrator1, write_conf +from spras.omicsintegrator1 import OmicsIntegrator1, write_conf TEST_DIR = 'test/OmicsIntegrator1/' OUT_FILE = TEST_DIR+'output/test_optimalForest.sif' diff --git a/test/OmicsIntegrator2/test_oi2.py b/test/OmicsIntegrator2/test_oi2.py index 9470649d..b0ba3ce3 100644 --- a/test/OmicsIntegrator2/test_oi2.py +++ b/test/OmicsIntegrator2/test_oi2.py @@ -3,7 +3,7 @@ import pytest -from src.omicsintegrator2 import OmicsIntegrator2 +from spras.omicsintegrator2 import OmicsIntegrator2 TEST_DIR = 'test/OmicsIntegrator2/' EDGE_FILE = TEST_DIR+'input/oi2-edges.txt' diff --git a/test/PathLinker/test_pathlinker.py b/test/PathLinker/test_pathlinker.py index cde24a84..0ddb3a84 100644 --- a/test/PathLinker/test_pathlinker.py +++ b/test/PathLinker/test_pathlinker.py @@ -3,7 +3,7 @@ import pytest -from src.pathlinker import PathLinker +from spras.pathlinker import PathLinker TEST_DIR = 'test/PathLinker/' OUT_FILE_DEFAULT = TEST_DIR+'output/pathlinker-ranked-edges.txt' diff --git a/test/analysis/test_analysis.py b/test/analysis/test_analysis.py index de157ab3..002c266f 100644 --- a/test/analysis/test_analysis.py +++ b/test/analysis/test_analysis.py @@ -1,5 +1,5 @@ -import src.analysis.graphspace as graphspace -import src.analysis.summary as summary +import spras.analysis.graphspace as graphspace +import spras.analysis.summary as summary TEST_DIR = 'test/analysis/' diff --git a/test/analysis/test_cytoscape.py b/test/analysis/test_cytoscape.py index 3ac5eca3..6ea0daff 100644 --- a/test/analysis/test_cytoscape.py +++ b/test/analysis/test_cytoscape.py @@ -3,7 +3,7 @@ import pytest -from src.analysis.cytoscape import run_cytoscape +from spras.analysis.cytoscape import run_cytoscape INPUT_DIR = 'test/analysis/input/example/' INPUT_PATHWAYS = [INPUT_DIR + 'data0-meo-params-GKEDDFZ_pathway.txt', diff --git a/test/analysis/test_summary.py b/test/analysis/test_summary.py index 2b6cced1..bf7c093e 100644 --- a/test/analysis/test_summary.py +++ b/test/analysis/test_summary.py @@ -2,7 +2,7 @@ import pandas as pd -from src.analysis.summary import summarize_networks +from spras.analysis.summary import summarize_networks # Notes: # - Column labels are required in the node table diff --git a/test/ml/test_ml.py b/test/ml/test_ml.py index aefd0419..c8ac385b 100644 --- a/test/ml/test_ml.py +++ b/test/ml/test_ml.py @@ -3,7 +3,7 @@ import pandas as pd -import src.analysis.ml as ml +import spras.analysis.ml as ml INPUT_DIR = 'test/ml/input/' OUT_DIR = 'test/ml/output/' diff --git a/test/test_prepare_inputs.py b/test/test_prepare_inputs.py index e0c2e4cd..afab0882 100644 --- a/test/test_prepare_inputs.py +++ b/test/test_prepare_inputs.py @@ -3,7 +3,7 @@ import yaml -from src import runner +from spras import runner config_loc = os.path.join("config", "config.yaml") diff --git a/test/test_util.py b/test/test_util.py index 968ec716..10b36c5e 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -2,7 +2,7 @@ import pytest -from src.util import ( +from spras.util import ( convert_docker_path, hash_params_sha1_base32, prepare_path_docker,